1 /* BFD back-end for MS-DOS executables. 2 Copyright (C) 1990-2024 Free Software Foundation, Inc. 3 Written by Bryan Ford of the University of Utah. 4 5 Contributed by the Center for Software Science at the 6 University of Utah (pa-gdb-bugs@cs.utah.edu). 7 8 This file is part of BFD, the Binary File Descriptor library. 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 23 MA 02110-1301, USA. */ 24 25 26 #include "sysdep.h" 27 #include "bfd.h" 28 #include "libbfd.h" 29 #include "libaout.h" 30 #include "coff/msdos.h" 31 32 #define EXE_LOAD_HIGH 0x0000 33 #define EXE_LOAD_LOW 0xffff 34 #define EXE_PAGE_SIZE 512 35 36 static bool 37 msdos_mkobject (bfd *abfd) 38 { 39 bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_i386_i8086); 40 41 return aout_32_mkobject (abfd); 42 } 43 44 static bfd_cleanup 45 msdos_object_p (bfd *abfd) 46 { 47 struct external_DOS_hdr hdr; 48 bfd_byte buffer[2]; 49 asection *section; 50 bfd_size_type size; 51 52 if (bfd_seek (abfd, 0, SEEK_SET) != 0 53 || (size = bfd_read (&hdr, sizeof (hdr), abfd)) + 1 < DOS_HDR_SIZE + 1) 54 { 55 if (bfd_get_error () != bfd_error_system_call) 56 bfd_set_error (bfd_error_wrong_format); 57 return NULL; 58 } 59 60 if (H_GET_16 (abfd, hdr.e_magic) != IMAGE_DOS_SIGNATURE) 61 { 62 bfd_set_error (bfd_error_wrong_format); 63 return NULL; 64 } 65 66 /* Check that this isn't actually a PE, NE, or LE file. If it is, the 67 e_lfanew field will be valid and point to a header beginning with one of 68 the relevant signatures. If not, e_lfanew might point to anything, so 69 don't bail if we can't read there. */ 70 if (size < offsetof (struct external_DOS_hdr, e_lfanew) + 4 71 || H_GET_16 (abfd, hdr.e_cparhdr) < 4) 72 ; 73 else if (bfd_seek (abfd, H_GET_32 (abfd, hdr.e_lfanew), SEEK_SET) != 0 74 || bfd_read (buffer, 2, abfd) != 2) 75 { 76 if (bfd_get_error () == bfd_error_system_call) 77 return NULL; 78 } 79 else 80 { 81 if (H_GET_16 (abfd, buffer) == IMAGE_NT_SIGNATURE 82 || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE 83 || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE_LE 84 || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE_LX) 85 { 86 bfd_set_error (bfd_error_wrong_format); 87 return NULL; 88 } 89 } 90 91 if (!msdos_mkobject (abfd)) 92 return NULL; 93 94 abfd->flags = EXEC_P; 95 abfd->start_address = H_GET_16 (abfd, hdr.e_ip); 96 97 section = bfd_make_section (abfd, ".text"); 98 if (section == NULL) 99 return NULL; 100 101 section->flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS); 102 section->filepos = H_GET_16 (abfd, hdr.e_cparhdr) * 16; 103 size = (H_GET_16 (abfd, hdr.e_cp) - 1) * EXE_PAGE_SIZE - section->filepos; 104 size += H_GET_16 (abfd, hdr.e_cblp); 105 106 /* Check that the size is valid. */ 107 if (bfd_seek (abfd, section->filepos + size, SEEK_SET) != 0) 108 { 109 if (bfd_get_error () != bfd_error_system_call) 110 bfd_set_error (bfd_error_wrong_format); 111 return NULL; 112 } 113 114 bfd_set_section_size (section, size); 115 section->alignment_power = 4; 116 117 return _bfd_no_cleanup; 118 } 119 120 static int 121 msdos_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, 122 struct bfd_link_info *info ATTRIBUTE_UNUSED) 123 { 124 return 0; 125 } 126 127 static bool 128 msdos_write_object_contents (bfd *abfd) 129 { 130 static char hdr[EXE_PAGE_SIZE]; 131 file_ptr outfile_size = sizeof(hdr); 132 bfd_vma high_vma = 0; 133 asection *sec; 134 135 /* Find the total size of the program on disk and in memory. */ 136 for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) 137 { 138 if (sec->size == 0) 139 continue; 140 if (bfd_section_flags (sec) & SEC_ALLOC) 141 { 142 bfd_vma sec_vma = bfd_section_vma (sec) + sec->size; 143 if (sec_vma > high_vma) 144 high_vma = sec_vma; 145 } 146 if (bfd_section_flags (sec) & SEC_LOAD) 147 { 148 file_ptr sec_end = (sizeof (hdr) 149 + bfd_section_vma (sec) 150 + sec->size); 151 if (sec_end > outfile_size) 152 outfile_size = sec_end; 153 } 154 } 155 156 /* Make sure the program isn't too big. */ 157 if (high_vma > (bfd_vma)0xffff) 158 { 159 bfd_set_error(bfd_error_file_too_big); 160 return false; 161 } 162 163 /* Constants. */ 164 H_PUT_16 (abfd, IMAGE_DOS_SIGNATURE, &hdr[0]); 165 H_PUT_16 (abfd, EXE_PAGE_SIZE / 16, &hdr[8]); 166 H_PUT_16 (abfd, EXE_LOAD_LOW, &hdr[12]); 167 H_PUT_16 (abfd, 0x3e, &hdr[24]); 168 H_PUT_16 (abfd, 0x0001, &hdr[28]); /* XXX??? */ 169 H_PUT_16 (abfd, 0x30fb, &hdr[30]); /* XXX??? */ 170 H_PUT_16 (abfd, 0x726a, &hdr[32]); /* XXX??? */ 171 172 /* Bytes in last page (0 = full page). */ 173 H_PUT_16 (abfd, outfile_size & (EXE_PAGE_SIZE - 1), &hdr[2]); 174 175 /* Number of pages. */ 176 H_PUT_16 (abfd, (outfile_size + EXE_PAGE_SIZE - 1) / EXE_PAGE_SIZE, &hdr[4]); 177 178 /* Set the initial stack pointer to the end of the bss. 179 The program's crt0 code must relocate it to a real stack. */ 180 H_PUT_16 (abfd, high_vma, &hdr[16]); 181 182 if (bfd_seek (abfd, 0, SEEK_SET) != 0 183 || bfd_write (hdr, sizeof (hdr), abfd) != sizeof (hdr)) 184 return false; 185 186 return true; 187 } 188 189 static bool 190 msdos_set_section_contents (bfd *abfd, 191 sec_ptr section, 192 const void *location, 193 file_ptr offset, 194 bfd_size_type count) 195 { 196 197 if (count == 0) 198 return true; 199 200 section->filepos = EXE_PAGE_SIZE + bfd_section_vma (section); 201 202 if (bfd_section_flags (section) & SEC_LOAD) 203 { 204 if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 205 || bfd_write (location, count, abfd) != count) 206 return false; 207 } 208 209 return true; 210 } 211 212 213 214 #define msdos_make_empty_symbol aout_32_make_empty_symbol 215 #define msdos_bfd_reloc_type_lookup aout_32_reloc_type_lookup 216 #define msdos_bfd_reloc_name_lookup aout_32_reloc_name_lookup 217 218 #define msdos_close_and_cleanup _bfd_generic_close_and_cleanup 219 #define msdos_bfd_free_cached_info _bfd_generic_bfd_free_cached_info 220 #define msdos_new_section_hook _bfd_generic_new_section_hook 221 #define msdos_get_section_contents _bfd_generic_get_section_contents 222 #define msdos_bfd_get_relocated_section_contents \ 223 bfd_generic_get_relocated_section_contents 224 #define msdos_bfd_relax_section bfd_generic_relax_section 225 #define msdos_bfd_gc_sections bfd_generic_gc_sections 226 #define msdos_bfd_lookup_section_flags bfd_generic_lookup_section_flags 227 #define msdos_bfd_merge_sections bfd_generic_merge_sections 228 #define msdos_bfd_is_group_section bfd_generic_is_group_section 229 #define msdos_bfd_group_name bfd_generic_group_name 230 #define msdos_bfd_discard_group bfd_generic_discard_group 231 #define msdos_section_already_linked \ 232 _bfd_generic_section_already_linked 233 #define msdos_bfd_define_common_symbol bfd_generic_define_common_symbol 234 #define msdos_bfd_link_hide_symbol _bfd_generic_link_hide_symbol 235 #define msdos_bfd_define_start_stop bfd_generic_define_start_stop 236 #define msdos_bfd_link_hash_table_create _bfd_generic_link_hash_table_create 237 #define msdos_bfd_link_add_symbols _bfd_generic_link_add_symbols 238 #define msdos_bfd_link_just_syms _bfd_generic_link_just_syms 239 #define msdos_bfd_copy_link_hash_symbol_type \ 240 _bfd_generic_copy_link_hash_symbol_type 241 #define msdos_bfd_final_link _bfd_generic_final_link 242 #define msdos_bfd_link_split_section _bfd_generic_link_split_section 243 #define msdos_set_arch_mach _bfd_generic_set_arch_mach 244 #define msdos_bfd_link_check_relocs _bfd_generic_link_check_relocs 245 246 #define msdos_get_symtab_upper_bound _bfd_nosymbols_get_symtab_upper_bound 247 #define msdos_canonicalize_symtab _bfd_nosymbols_canonicalize_symtab 248 #define msdos_print_symbol _bfd_nosymbols_print_symbol 249 #define msdos_get_symbol_info _bfd_nosymbols_get_symbol_info 250 #define msdos_get_symbol_version_string \ 251 _bfd_nosymbols_get_symbol_version_string 252 #define msdos_find_nearest_line _bfd_nosymbols_find_nearest_line 253 #define msdos_find_nearest_line_with_alt _bfd_nosymbols_find_nearest_line_with_alt 254 #define msdos_find_line _bfd_nosymbols_find_line 255 #define msdos_find_inliner_info _bfd_nosymbols_find_inliner_info 256 #define msdos_get_lineno _bfd_nosymbols_get_lineno 257 #define msdos_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false 258 #define msdos_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name 259 #define msdos_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol 260 #define msdos_read_minisymbols _bfd_nosymbols_read_minisymbols 261 #define msdos_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol 262 263 #define msdos_canonicalize_reloc _bfd_norelocs_canonicalize_reloc 264 #define msdos_set_reloc _bfd_norelocs_set_reloc 265 #define msdos_get_reloc_upper_bound _bfd_norelocs_get_reloc_upper_bound 266 #define msdos_32_bfd_link_split_section _bfd_generic_link_split_section 267 268 const bfd_target i386_msdos_vec = 269 { 270 "msdos", /* name */ 271 bfd_target_msdos_flavour, 272 BFD_ENDIAN_LITTLE, /* target byte order */ 273 BFD_ENDIAN_LITTLE, /* target headers byte order */ 274 (EXEC_P), /* object flags */ 275 (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS 276 | SEC_ALLOC | SEC_LOAD), /* section flags */ 277 0, /* leading underscore */ 278 ' ', /* ar_pad_char */ 279 16, /* ar_max_namelen */ 280 0, /* match priority. */ 281 TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ 282 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 283 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 284 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ 285 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 286 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 287 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ 288 289 { 290 _bfd_dummy_target, 291 msdos_object_p, /* bfd_check_format */ 292 _bfd_dummy_target, 293 _bfd_dummy_target, 294 }, 295 { 296 _bfd_bool_bfd_false_error, 297 msdos_mkobject, 298 _bfd_generic_mkarchive, 299 _bfd_bool_bfd_false_error, 300 }, 301 { /* bfd_write_contents */ 302 _bfd_bool_bfd_false_error, 303 msdos_write_object_contents, 304 _bfd_write_archive_contents, 305 _bfd_bool_bfd_false_error, 306 }, 307 308 BFD_JUMP_TABLE_GENERIC (msdos), 309 BFD_JUMP_TABLE_COPY (_bfd_generic), 310 BFD_JUMP_TABLE_CORE (_bfd_nocore), 311 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 312 BFD_JUMP_TABLE_SYMBOLS (msdos), 313 BFD_JUMP_TABLE_RELOCS (msdos), 314 BFD_JUMP_TABLE_WRITE (msdos), 315 BFD_JUMP_TABLE_LINK (msdos), 316 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 317 318 NULL, 319 320 NULL 321 }; 322 323 324