175fd0b74Schristos /* BFD back-end for MS-DOS executables.
2*e992f068Schristos Copyright (C) 1990-2022 Free Software Foundation, Inc.
375fd0b74Schristos Written by Bryan Ford of the University of Utah.
475fd0b74Schristos
575fd0b74Schristos Contributed by the Center for Software Science at the
675fd0b74Schristos University of Utah (pa-gdb-bugs@cs.utah.edu).
775fd0b74Schristos
875fd0b74Schristos This file is part of BFD, the Binary File Descriptor library.
975fd0b74Schristos
1075fd0b74Schristos This program is free software; you can redistribute it and/or modify
1175fd0b74Schristos it under the terms of the GNU General Public License as published by
1275fd0b74Schristos the Free Software Foundation; either version 3 of the License, or
1375fd0b74Schristos (at your option) any later version.
1475fd0b74Schristos
1575fd0b74Schristos This program is distributed in the hope that it will be useful,
1675fd0b74Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1775fd0b74Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1875fd0b74Schristos GNU General Public License for more details.
1975fd0b74Schristos
2075fd0b74Schristos You should have received a copy of the GNU General Public License
2175fd0b74Schristos along with this program; if not, write to the Free Software
2275fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2375fd0b74Schristos MA 02110-1301, USA. */
2475fd0b74Schristos
2575fd0b74Schristos
2675fd0b74Schristos #include "sysdep.h"
2775fd0b74Schristos #include "bfd.h"
2875fd0b74Schristos #include "libbfd.h"
2975fd0b74Schristos #include "libaout.h"
30ede78133Schristos #include "coff/msdos.h"
3175fd0b74Schristos
3275fd0b74Schristos #define EXE_LOAD_HIGH 0x0000
3375fd0b74Schristos #define EXE_LOAD_LOW 0xffff
3475fd0b74Schristos #define EXE_PAGE_SIZE 512
3575fd0b74Schristos
36*e992f068Schristos static bool
msdos_mkobject(bfd * abfd)37ede78133Schristos msdos_mkobject (bfd *abfd)
38ede78133Schristos {
39ede78133Schristos bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_i386_i8086);
40ede78133Schristos
41ede78133Schristos return aout_32_mkobject (abfd);
42ede78133Schristos }
43ede78133Schristos
44*e992f068Schristos static bfd_cleanup
msdos_object_p(bfd * abfd)45ede78133Schristos msdos_object_p (bfd *abfd)
46ede78133Schristos {
47ede78133Schristos struct external_DOS_hdr hdr;
48ede78133Schristos bfd_byte buffer[2];
49ede78133Schristos asection *section;
50*e992f068Schristos bfd_size_type size;
51ede78133Schristos
52ede78133Schristos if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
53*e992f068Schristos || (size = bfd_bread (&hdr, sizeof (hdr), abfd)) + 1 < DOS_HDR_SIZE + 1)
54ede78133Schristos {
55ede78133Schristos if (bfd_get_error () != bfd_error_system_call)
56ede78133Schristos bfd_set_error (bfd_error_wrong_format);
57ede78133Schristos return NULL;
58ede78133Schristos }
59ede78133Schristos
60ede78133Schristos if (H_GET_16 (abfd, hdr.e_magic) != IMAGE_DOS_SIGNATURE)
61ede78133Schristos {
62ede78133Schristos bfd_set_error (bfd_error_wrong_format);
63ede78133Schristos return NULL;
64ede78133Schristos }
65ede78133Schristos
66ede78133Schristos /* Check that this isn't actually a PE, NE, or LE file. If it is, the
67ede78133Schristos e_lfanew field will be valid and point to a header beginning with one of
68ede78133Schristos the relevant signatures. If not, e_lfanew might point to anything, so
69ede78133Schristos don't bail if we can't read there. */
70*e992f068Schristos if (size < offsetof (struct external_DOS_hdr, e_lfanew) + 4
71*e992f068Schristos || H_GET_16 (abfd, hdr.e_cparhdr) < 4)
72*e992f068Schristos ;
73*e992f068Schristos else if (bfd_seek (abfd, H_GET_32 (abfd, hdr.e_lfanew), SEEK_SET) != 0
74ede78133Schristos || bfd_bread (buffer, (bfd_size_type) 2, abfd) != 2)
75ede78133Schristos {
76ede78133Schristos if (bfd_get_error () == bfd_error_system_call)
77ede78133Schristos return NULL;
78ede78133Schristos }
79ede78133Schristos else
80ede78133Schristos {
81ede78133Schristos if (H_GET_16 (abfd, buffer) == IMAGE_NT_SIGNATURE
82ede78133Schristos || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE
83ede78133Schristos || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE_LE
84ede78133Schristos || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE_LX)
85ede78133Schristos {
86ede78133Schristos bfd_set_error (bfd_error_wrong_format);
87ede78133Schristos return NULL;
88ede78133Schristos }
89ede78133Schristos }
90ede78133Schristos
91ede78133Schristos if (!msdos_mkobject (abfd))
92ede78133Schristos return NULL;
93ede78133Schristos
94ede78133Schristos abfd->flags = EXEC_P;
95ede78133Schristos abfd->start_address = H_GET_16 (abfd, hdr.e_ip);
96ede78133Schristos
97ede78133Schristos section = bfd_make_section (abfd, ".text");
98ede78133Schristos if (section == NULL)
99ede78133Schristos return NULL;
100ede78133Schristos
101ede78133Schristos section->flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS);
102ede78133Schristos section->filepos = H_GET_16 (abfd, hdr.e_cparhdr) * 16;
103ede78133Schristos size = (H_GET_16 (abfd, hdr.e_cp) - 1) * EXE_PAGE_SIZE - section->filepos;
104ede78133Schristos size += H_GET_16 (abfd, hdr.e_cblp);
105ede78133Schristos
106ede78133Schristos /* Check that the size is valid. */
107*e992f068Schristos if (bfd_seek (abfd, section->filepos + size, SEEK_SET) != 0)
108ede78133Schristos {
109ede78133Schristos if (bfd_get_error () != bfd_error_system_call)
110ede78133Schristos bfd_set_error (bfd_error_wrong_format);
111ede78133Schristos return NULL;
112ede78133Schristos }
113ede78133Schristos
114012573ebSchristos bfd_set_section_size (section, size);
115ede78133Schristos section->alignment_power = 4;
116ede78133Schristos
117*e992f068Schristos return _bfd_no_cleanup;
118ede78133Schristos }
119ede78133Schristos
12075fd0b74Schristos static int
msdos_sizeof_headers(bfd * abfd ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED)12175fd0b74Schristos msdos_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
12275fd0b74Schristos struct bfd_link_info *info ATTRIBUTE_UNUSED)
12375fd0b74Schristos {
12475fd0b74Schristos return 0;
12575fd0b74Schristos }
12675fd0b74Schristos
127*e992f068Schristos static bool
msdos_write_object_contents(bfd * abfd)12875fd0b74Schristos msdos_write_object_contents (bfd *abfd)
12975fd0b74Schristos {
13075fd0b74Schristos static char hdr[EXE_PAGE_SIZE];
13175fd0b74Schristos file_ptr outfile_size = sizeof(hdr);
13275fd0b74Schristos bfd_vma high_vma = 0;
13375fd0b74Schristos asection *sec;
13475fd0b74Schristos
13575fd0b74Schristos /* Find the total size of the program on disk and in memory. */
13675fd0b74Schristos for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next)
13775fd0b74Schristos {
13875fd0b74Schristos if (sec->size == 0)
13975fd0b74Schristos continue;
140012573ebSchristos if (bfd_section_flags (sec) & SEC_ALLOC)
14175fd0b74Schristos {
142012573ebSchristos bfd_vma sec_vma = bfd_section_vma (sec) + sec->size;
14375fd0b74Schristos if (sec_vma > high_vma)
14475fd0b74Schristos high_vma = sec_vma;
14575fd0b74Schristos }
146012573ebSchristos if (bfd_section_flags (sec) & SEC_LOAD)
14775fd0b74Schristos {
14875fd0b74Schristos file_ptr sec_end = (sizeof (hdr)
149012573ebSchristos + bfd_section_vma (sec)
15075fd0b74Schristos + sec->size);
15175fd0b74Schristos if (sec_end > outfile_size)
15275fd0b74Schristos outfile_size = sec_end;
15375fd0b74Schristos }
15475fd0b74Schristos }
15575fd0b74Schristos
15675fd0b74Schristos /* Make sure the program isn't too big. */
15775fd0b74Schristos if (high_vma > (bfd_vma)0xffff)
15875fd0b74Schristos {
15975fd0b74Schristos bfd_set_error(bfd_error_file_too_big);
160*e992f068Schristos return false;
16175fd0b74Schristos }
16275fd0b74Schristos
16375fd0b74Schristos /* Constants. */
164ede78133Schristos H_PUT_16 (abfd, IMAGE_DOS_SIGNATURE, &hdr[0]);
16575fd0b74Schristos H_PUT_16 (abfd, EXE_PAGE_SIZE / 16, &hdr[8]);
16675fd0b74Schristos H_PUT_16 (abfd, EXE_LOAD_LOW, &hdr[12]);
16775fd0b74Schristos H_PUT_16 (abfd, 0x3e, &hdr[24]);
16875fd0b74Schristos H_PUT_16 (abfd, 0x0001, &hdr[28]); /* XXX??? */
16975fd0b74Schristos H_PUT_16 (abfd, 0x30fb, &hdr[30]); /* XXX??? */
17075fd0b74Schristos H_PUT_16 (abfd, 0x726a, &hdr[32]); /* XXX??? */
17175fd0b74Schristos
17275fd0b74Schristos /* Bytes in last page (0 = full page). */
17375fd0b74Schristos H_PUT_16 (abfd, outfile_size & (EXE_PAGE_SIZE - 1), &hdr[2]);
17475fd0b74Schristos
17575fd0b74Schristos /* Number of pages. */
17675fd0b74Schristos H_PUT_16 (abfd, (outfile_size + EXE_PAGE_SIZE - 1) / EXE_PAGE_SIZE, &hdr[4]);
17775fd0b74Schristos
17875fd0b74Schristos /* Set the initial stack pointer to the end of the bss.
17975fd0b74Schristos The program's crt0 code must relocate it to a real stack. */
18075fd0b74Schristos H_PUT_16 (abfd, high_vma, &hdr[16]);
18175fd0b74Schristos
18275fd0b74Schristos if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
18375fd0b74Schristos || bfd_bwrite (hdr, (bfd_size_type) sizeof(hdr), abfd) != sizeof(hdr))
184*e992f068Schristos return false;
18575fd0b74Schristos
186*e992f068Schristos return true;
18775fd0b74Schristos }
18875fd0b74Schristos
189*e992f068Schristos static bool
msdos_set_section_contents(bfd * abfd,sec_ptr section,const void * location,file_ptr offset,bfd_size_type count)19075fd0b74Schristos msdos_set_section_contents (bfd *abfd,
19175fd0b74Schristos sec_ptr section,
19275fd0b74Schristos const void *location,
19375fd0b74Schristos file_ptr offset,
19475fd0b74Schristos bfd_size_type count)
19575fd0b74Schristos {
19675fd0b74Schristos
19775fd0b74Schristos if (count == 0)
198*e992f068Schristos return true;
19975fd0b74Schristos
200012573ebSchristos section->filepos = EXE_PAGE_SIZE + bfd_section_vma (section);
20175fd0b74Schristos
202012573ebSchristos if (bfd_section_flags (section) & SEC_LOAD)
20375fd0b74Schristos {
20475fd0b74Schristos if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
20575fd0b74Schristos || bfd_bwrite (location, count, abfd) != count)
206*e992f068Schristos return false;
20775fd0b74Schristos }
20875fd0b74Schristos
209*e992f068Schristos return true;
21075fd0b74Schristos }
21175fd0b74Schristos
21275fd0b74Schristos
21375fd0b74Schristos
21475fd0b74Schristos #define msdos_make_empty_symbol aout_32_make_empty_symbol
21575fd0b74Schristos #define msdos_bfd_reloc_type_lookup aout_32_reloc_type_lookup
21675fd0b74Schristos #define msdos_bfd_reloc_name_lookup aout_32_reloc_name_lookup
21775fd0b74Schristos
21875fd0b74Schristos #define msdos_close_and_cleanup _bfd_generic_close_and_cleanup
21975fd0b74Schristos #define msdos_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
22075fd0b74Schristos #define msdos_new_section_hook _bfd_generic_new_section_hook
22175fd0b74Schristos #define msdos_get_section_contents _bfd_generic_get_section_contents
22275fd0b74Schristos #define msdos_get_section_contents_in_window \
22375fd0b74Schristos _bfd_generic_get_section_contents_in_window
22475fd0b74Schristos #define msdos_bfd_get_relocated_section_contents \
22575fd0b74Schristos bfd_generic_get_relocated_section_contents
22675fd0b74Schristos #define msdos_bfd_relax_section bfd_generic_relax_section
22775fd0b74Schristos #define msdos_bfd_gc_sections bfd_generic_gc_sections
22875fd0b74Schristos #define msdos_bfd_lookup_section_flags bfd_generic_lookup_section_flags
22975fd0b74Schristos #define msdos_bfd_merge_sections bfd_generic_merge_sections
23075fd0b74Schristos #define msdos_bfd_is_group_section bfd_generic_is_group_section
231012573ebSchristos #define msdos_bfd_group_name bfd_generic_group_name
23275fd0b74Schristos #define msdos_bfd_discard_group bfd_generic_discard_group
23375fd0b74Schristos #define msdos_section_already_linked \
23475fd0b74Schristos _bfd_generic_section_already_linked
23575fd0b74Schristos #define msdos_bfd_define_common_symbol bfd_generic_define_common_symbol
236ede78133Schristos #define msdos_bfd_link_hide_symbol _bfd_generic_link_hide_symbol
237ede78133Schristos #define msdos_bfd_define_start_stop bfd_generic_define_start_stop
23875fd0b74Schristos #define msdos_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
23975fd0b74Schristos #define msdos_bfd_link_add_symbols _bfd_generic_link_add_symbols
24075fd0b74Schristos #define msdos_bfd_link_just_syms _bfd_generic_link_just_syms
24175fd0b74Schristos #define msdos_bfd_copy_link_hash_symbol_type \
24275fd0b74Schristos _bfd_generic_copy_link_hash_symbol_type
24375fd0b74Schristos #define msdos_bfd_final_link _bfd_generic_final_link
24475fd0b74Schristos #define msdos_bfd_link_split_section _bfd_generic_link_split_section
24575fd0b74Schristos #define msdos_set_arch_mach _bfd_generic_set_arch_mach
24675fd0b74Schristos #define msdos_bfd_link_check_relocs _bfd_generic_link_check_relocs
24775fd0b74Schristos
24875fd0b74Schristos #define msdos_get_symtab_upper_bound _bfd_nosymbols_get_symtab_upper_bound
24975fd0b74Schristos #define msdos_canonicalize_symtab _bfd_nosymbols_canonicalize_symtab
25075fd0b74Schristos #define msdos_print_symbol _bfd_nosymbols_print_symbol
25175fd0b74Schristos #define msdos_get_symbol_info _bfd_nosymbols_get_symbol_info
25275fd0b74Schristos #define msdos_get_symbol_version_string \
25375fd0b74Schristos _bfd_nosymbols_get_symbol_version_string
25475fd0b74Schristos #define msdos_find_nearest_line _bfd_nosymbols_find_nearest_line
25575fd0b74Schristos #define msdos_find_line _bfd_nosymbols_find_line
25675fd0b74Schristos #define msdos_find_inliner_info _bfd_nosymbols_find_inliner_info
25775fd0b74Schristos #define msdos_get_lineno _bfd_nosymbols_get_lineno
258ede78133Schristos #define msdos_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false
25975fd0b74Schristos #define msdos_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name
26075fd0b74Schristos #define msdos_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
26175fd0b74Schristos #define msdos_read_minisymbols _bfd_nosymbols_read_minisymbols
26275fd0b74Schristos #define msdos_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol
26375fd0b74Schristos
26475fd0b74Schristos #define msdos_canonicalize_reloc _bfd_norelocs_canonicalize_reloc
265ede78133Schristos #define msdos_set_reloc _bfd_norelocs_set_reloc
26675fd0b74Schristos #define msdos_get_reloc_upper_bound _bfd_norelocs_get_reloc_upper_bound
26775fd0b74Schristos #define msdos_32_bfd_link_split_section _bfd_generic_link_split_section
26875fd0b74Schristos
26975fd0b74Schristos const bfd_target i386_msdos_vec =
27075fd0b74Schristos {
27175fd0b74Schristos "msdos", /* name */
27275fd0b74Schristos bfd_target_msdos_flavour,
27375fd0b74Schristos BFD_ENDIAN_LITTLE, /* target byte order */
27475fd0b74Schristos BFD_ENDIAN_LITTLE, /* target headers byte order */
27575fd0b74Schristos (EXEC_P), /* object flags */
27675fd0b74Schristos (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS
27775fd0b74Schristos | SEC_ALLOC | SEC_LOAD), /* section flags */
27875fd0b74Schristos 0, /* leading underscore */
27975fd0b74Schristos ' ', /* ar_pad_char */
28075fd0b74Schristos 16, /* ar_max_namelen */
28175fd0b74Schristos 0, /* match priority. */
282*e992f068Schristos TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */
28375fd0b74Schristos bfd_getl64, bfd_getl_signed_64, bfd_putl64,
28475fd0b74Schristos bfd_getl32, bfd_getl_signed_32, bfd_putl32,
28575fd0b74Schristos bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
28675fd0b74Schristos bfd_getl64, bfd_getl_signed_64, bfd_putl64,
28775fd0b74Schristos bfd_getl32, bfd_getl_signed_32, bfd_putl32,
28875fd0b74Schristos bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
28975fd0b74Schristos
29075fd0b74Schristos {
29175fd0b74Schristos _bfd_dummy_target,
292ede78133Schristos msdos_object_p, /* bfd_check_format */
29375fd0b74Schristos _bfd_dummy_target,
29475fd0b74Schristos _bfd_dummy_target,
29575fd0b74Schristos },
29675fd0b74Schristos {
297ede78133Schristos _bfd_bool_bfd_false_error,
29875fd0b74Schristos msdos_mkobject,
29975fd0b74Schristos _bfd_generic_mkarchive,
300ede78133Schristos _bfd_bool_bfd_false_error,
30175fd0b74Schristos },
30275fd0b74Schristos { /* bfd_write_contents */
303ede78133Schristos _bfd_bool_bfd_false_error,
30475fd0b74Schristos msdos_write_object_contents,
30575fd0b74Schristos _bfd_write_archive_contents,
306ede78133Schristos _bfd_bool_bfd_false_error,
30775fd0b74Schristos },
30875fd0b74Schristos
30975fd0b74Schristos BFD_JUMP_TABLE_GENERIC (msdos),
31075fd0b74Schristos BFD_JUMP_TABLE_COPY (_bfd_generic),
31175fd0b74Schristos BFD_JUMP_TABLE_CORE (_bfd_nocore),
31275fd0b74Schristos BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
31375fd0b74Schristos BFD_JUMP_TABLE_SYMBOLS (msdos),
31475fd0b74Schristos BFD_JUMP_TABLE_RELOCS (msdos),
31575fd0b74Schristos BFD_JUMP_TABLE_WRITE (msdos),
31675fd0b74Schristos BFD_JUMP_TABLE_LINK (msdos),
31775fd0b74Schristos BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
31875fd0b74Schristos
31975fd0b74Schristos NULL,
32075fd0b74Schristos
32175fd0b74Schristos NULL
32275fd0b74Schristos };
32375fd0b74Schristos
32475fd0b74Schristos
325