1 /* BFD back-end for MS-DOS executables. 2 Copyright (C) 1990-2020 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 bfd_boolean 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 const bfd_target * 45 msdos_object_p (bfd *abfd) 46 { 47 struct external_DOS_hdr hdr; 48 bfd_byte buffer[2]; 49 asection *section; 50 unsigned int size; 51 52 if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 53 || bfd_bread (&hdr, (bfd_size_type) sizeof (hdr), abfd) < DOS_HDR_SIZE) 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 (H_GET_16 (abfd, hdr.e_cparhdr) < 4 71 || bfd_seek (abfd, (file_ptr) H_GET_32 (abfd, hdr.e_lfanew), SEEK_SET) != 0 72 || bfd_bread (buffer, (bfd_size_type) 2, abfd) != 2) 73 { 74 if (bfd_get_error () == bfd_error_system_call) 75 return NULL; 76 } 77 else 78 { 79 if (H_GET_16 (abfd, buffer) == IMAGE_NT_SIGNATURE 80 || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE 81 || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE_LE 82 || H_GET_16 (abfd, buffer) == IMAGE_OS2_SIGNATURE_LX) 83 { 84 bfd_set_error (bfd_error_wrong_format); 85 return NULL; 86 } 87 } 88 89 if (!msdos_mkobject (abfd)) 90 return NULL; 91 92 abfd->flags = EXEC_P; 93 abfd->start_address = H_GET_16 (abfd, hdr.e_ip); 94 95 section = bfd_make_section (abfd, ".text"); 96 if (section == NULL) 97 return NULL; 98 99 section->flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS); 100 section->filepos = H_GET_16 (abfd, hdr.e_cparhdr) * 16; 101 size = (H_GET_16 (abfd, hdr.e_cp) - 1) * EXE_PAGE_SIZE - section->filepos; 102 size += H_GET_16 (abfd, hdr.e_cblp); 103 104 /* Check that the size is valid. */ 105 if (bfd_seek (abfd, (file_ptr) (section->filepos + size), SEEK_SET) != 0) 106 { 107 if (bfd_get_error () != bfd_error_system_call) 108 bfd_set_error (bfd_error_wrong_format); 109 return NULL; 110 } 111 112 bfd_set_section_size (section, size); 113 section->alignment_power = 4; 114 115 return abfd->xvec; 116 } 117 118 static int 119 msdos_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, 120 struct bfd_link_info *info ATTRIBUTE_UNUSED) 121 { 122 return 0; 123 } 124 125 static bfd_boolean 126 msdos_write_object_contents (bfd *abfd) 127 { 128 static char hdr[EXE_PAGE_SIZE]; 129 file_ptr outfile_size = sizeof(hdr); 130 bfd_vma high_vma = 0; 131 asection *sec; 132 133 /* Find the total size of the program on disk and in memory. */ 134 for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) 135 { 136 if (sec->size == 0) 137 continue; 138 if (bfd_section_flags (sec) & SEC_ALLOC) 139 { 140 bfd_vma sec_vma = bfd_section_vma (sec) + sec->size; 141 if (sec_vma > high_vma) 142 high_vma = sec_vma; 143 } 144 if (bfd_section_flags (sec) & SEC_LOAD) 145 { 146 file_ptr sec_end = (sizeof (hdr) 147 + bfd_section_vma (sec) 148 + sec->size); 149 if (sec_end > outfile_size) 150 outfile_size = sec_end; 151 } 152 } 153 154 /* Make sure the program isn't too big. */ 155 if (high_vma > (bfd_vma)0xffff) 156 { 157 bfd_set_error(bfd_error_file_too_big); 158 return FALSE; 159 } 160 161 /* Constants. */ 162 H_PUT_16 (abfd, IMAGE_DOS_SIGNATURE, &hdr[0]); 163 H_PUT_16 (abfd, EXE_PAGE_SIZE / 16, &hdr[8]); 164 H_PUT_16 (abfd, EXE_LOAD_LOW, &hdr[12]); 165 H_PUT_16 (abfd, 0x3e, &hdr[24]); 166 H_PUT_16 (abfd, 0x0001, &hdr[28]); /* XXX??? */ 167 H_PUT_16 (abfd, 0x30fb, &hdr[30]); /* XXX??? */ 168 H_PUT_16 (abfd, 0x726a, &hdr[32]); /* XXX??? */ 169 170 /* Bytes in last page (0 = full page). */ 171 H_PUT_16 (abfd, outfile_size & (EXE_PAGE_SIZE - 1), &hdr[2]); 172 173 /* Number of pages. */ 174 H_PUT_16 (abfd, (outfile_size + EXE_PAGE_SIZE - 1) / EXE_PAGE_SIZE, &hdr[4]); 175 176 /* Set the initial stack pointer to the end of the bss. 177 The program's crt0 code must relocate it to a real stack. */ 178 H_PUT_16 (abfd, high_vma, &hdr[16]); 179 180 if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 181 || bfd_bwrite (hdr, (bfd_size_type) sizeof(hdr), abfd) != sizeof(hdr)) 182 return FALSE; 183 184 return TRUE; 185 } 186 187 static bfd_boolean 188 msdos_set_section_contents (bfd *abfd, 189 sec_ptr section, 190 const void *location, 191 file_ptr offset, 192 bfd_size_type count) 193 { 194 195 if (count == 0) 196 return TRUE; 197 198 section->filepos = EXE_PAGE_SIZE + bfd_section_vma (section); 199 200 if (bfd_section_flags (section) & SEC_LOAD) 201 { 202 if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 203 || bfd_bwrite (location, count, abfd) != count) 204 return FALSE; 205 } 206 207 return TRUE; 208 } 209 210 211 212 #define msdos_make_empty_symbol aout_32_make_empty_symbol 213 #define msdos_bfd_reloc_type_lookup aout_32_reloc_type_lookup 214 #define msdos_bfd_reloc_name_lookup aout_32_reloc_name_lookup 215 216 #define msdos_close_and_cleanup _bfd_generic_close_and_cleanup 217 #define msdos_bfd_free_cached_info _bfd_generic_bfd_free_cached_info 218 #define msdos_new_section_hook _bfd_generic_new_section_hook 219 #define msdos_get_section_contents _bfd_generic_get_section_contents 220 #define msdos_get_section_contents_in_window \ 221 _bfd_generic_get_section_contents_in_window 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_line _bfd_nosymbols_find_line 254 #define msdos_find_inliner_info _bfd_nosymbols_find_inliner_info 255 #define msdos_get_lineno _bfd_nosymbols_get_lineno 256 #define msdos_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false 257 #define msdos_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name 258 #define msdos_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol 259 #define msdos_read_minisymbols _bfd_nosymbols_read_minisymbols 260 #define msdos_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol 261 262 #define msdos_canonicalize_reloc _bfd_norelocs_canonicalize_reloc 263 #define msdos_set_reloc _bfd_norelocs_set_reloc 264 #define msdos_get_reloc_upper_bound _bfd_norelocs_get_reloc_upper_bound 265 #define msdos_32_bfd_link_split_section _bfd_generic_link_split_section 266 267 const bfd_target i386_msdos_vec = 268 { 269 "msdos", /* name */ 270 bfd_target_msdos_flavour, 271 BFD_ENDIAN_LITTLE, /* target byte order */ 272 BFD_ENDIAN_LITTLE, /* target headers byte order */ 273 (EXEC_P), /* object flags */ 274 (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS 275 | SEC_ALLOC | SEC_LOAD), /* section flags */ 276 0, /* leading underscore */ 277 ' ', /* ar_pad_char */ 278 16, /* ar_max_namelen */ 279 0, /* match priority. */ 280 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 281 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 282 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ 283 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 284 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 285 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ 286 287 { 288 _bfd_dummy_target, 289 msdos_object_p, /* bfd_check_format */ 290 _bfd_dummy_target, 291 _bfd_dummy_target, 292 }, 293 { 294 _bfd_bool_bfd_false_error, 295 msdos_mkobject, 296 _bfd_generic_mkarchive, 297 _bfd_bool_bfd_false_error, 298 }, 299 { /* bfd_write_contents */ 300 _bfd_bool_bfd_false_error, 301 msdos_write_object_contents, 302 _bfd_write_archive_contents, 303 _bfd_bool_bfd_false_error, 304 }, 305 306 BFD_JUMP_TABLE_GENERIC (msdos), 307 BFD_JUMP_TABLE_COPY (_bfd_generic), 308 BFD_JUMP_TABLE_CORE (_bfd_nocore), 309 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 310 BFD_JUMP_TABLE_SYMBOLS (msdos), 311 BFD_JUMP_TABLE_RELOCS (msdos), 312 BFD_JUMP_TABLE_WRITE (msdos), 313 BFD_JUMP_TABLE_LINK (msdos), 314 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 315 316 NULL, 317 318 NULL 319 }; 320 321 322