xref: /netbsd-src/external/gpl3/binutils.old/dist/bfd/i386msdos.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
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