1 1.1 christos /* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub). 2 1.11 christos Copyright (C) 1997-2024 Free Software Foundation, Inc. 3 1.1 christos Written by Robert Hoehne. 4 1.1 christos 5 1.1 christos This file is part of BFD, the Binary File Descriptor library. 6 1.1 christos 7 1.1 christos This program is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the License, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos This program is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program; if not, write to the Free Software 19 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 20 1.1 christos MA 02110-1301, USA. */ 21 1.1 christos 22 1.1 christos /* This file handles now also stubbed coff images. The stub is a small 23 1.1 christos DOS executable program before the coff image to load it in memory 24 1.1 christos and execute it. This is needed, because DOS cannot run coff files. 25 1.1 christos 26 1.9 christos The COFF image is loaded in memory without the stub attached, so 27 1.9 christos all offsets are relative to the beginning of the image, not the 28 1.9 christos actual file. We handle this in bfd by setting bfd->origin to where 29 1.9 christos the COFF image starts. */ 30 1.1 christos 31 1.3 christos #define TARGET_SYM i386_coff_go32stubbed_vec 32 1.1 christos #define TARGET_NAME "coff-go32-exe" 33 1.1 christos #define TARGET_UNDERSCORE '_' 34 1.1 christos #define COFF_GO32_EXE 35 1.1 christos #define COFF_LONG_SECTION_NAMES 36 1.1 christos #define COFF_SUPPORT_GNU_LINKONCE 37 1.1 christos #define COFF_LONG_FILENAMES 38 1.1 christos 39 1.1 christos #define COFF_SECTION_ALIGNMENT_ENTRIES \ 40 1.1 christos { COFF_SECTION_NAME_EXACT_MATCH (".data"), \ 41 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ 42 1.1 christos { COFF_SECTION_NAME_EXACT_MATCH (".text"), \ 43 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ 44 1.1 christos { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ 45 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ 46 1.1 christos { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \ 47 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } 48 1.1 christos 49 1.9 christos /* Section contains extended relocations. */ 50 1.9 christos #define IMAGE_SCN_LNK_NRELOC_OVFL (0x01000000) 51 1.9 christos 52 1.1 christos #include "sysdep.h" 53 1.1 christos #include "bfd.h" 54 1.9 christos #include "coff/msdos.h" 55 1.1 christos 56 1.9 christos static bfd_cleanup go32exe_check_format (bfd *); 57 1.10 christos static bool go32exe_write_object_contents (bfd *); 58 1.10 christos static bool go32exe_mkobject (bfd *); 59 1.10 christos static bool go32exe_copy_private_bfd_data (bfd *, bfd *); 60 1.9 christos 61 1.9 christos /* Defined in coff-go32.c. */ 62 1.10 christos bool _bfd_go32_mkobject (bfd *); 63 1.9 christos void _bfd_go32_swap_scnhdr_in (bfd *, void *, void *); 64 1.9 christos unsigned int _bfd_go32_swap_scnhdr_out (bfd *, void *, void *); 65 1.9 christos 66 1.9 christos #define COFF_CHECK_FORMAT go32exe_check_format 67 1.9 christos #define COFF_WRITE_CONTENTS go32exe_write_object_contents 68 1.9 christos #define coff_mkobject go32exe_mkobject 69 1.9 christos #define coff_bfd_copy_private_bfd_data go32exe_copy_private_bfd_data 70 1.9 christos #define coff_SWAP_scnhdr_in _bfd_go32_swap_scnhdr_in 71 1.9 christos #define coff_SWAP_scnhdr_out _bfd_go32_swap_scnhdr_out 72 1.1 christos 73 1.1 christos #include "coff-i386.c" 74 1.1 christos 75 1.1 christos /* This macro is used, because I cannot assume the endianness of the 76 1.1 christos host system. */ 77 1.1 christos #define _H(index) (H_GET_16 (abfd, (header + index * 2))) 78 1.1 christos 79 1.1 christos /* These bytes are a 2048-byte DOS executable, which loads the COFF 80 1.1 christos image into memory and then runs it. It is called 'stub'. */ 81 1.9 christos #define GO32EXE_DEFAULT_STUB_SIZE 2048 82 1.9 christos static const unsigned char go32exe_default_stub[GO32EXE_DEFAULT_STUB_SIZE] = 83 1.1 christos { 84 1.1 christos #include "go32stub.h" 85 1.1 christos }; 86 1.1 christos 87 1.9 christos /* Temporary location for stub read from input file. */ 88 1.9 christos static char * go32exe_temp_stub = NULL; 89 1.9 christos static bfd_size_type go32exe_temp_stub_size = 0; 90 1.1 christos 91 1.1 christos /* That's the function, which creates the stub. There are 92 1.1 christos different cases from where the stub is taken. 93 1.1 christos At first the environment variable $(GO32STUB) is checked and then 94 1.1 christos $(STUB) if it was not set. 95 1.1 christos If it exists and points to a valid stub the stub is taken from 96 1.1 christos that file. This file can be also a whole executable file, because 97 1.1 christos the stub is computed from the exe information at the start of that 98 1.1 christos file. 99 1.1 christos 100 1.1 christos If there was any error, the standard stub (compiled in this file) 101 1.9 christos is taken. 102 1.9 christos 103 1.9 christos Ideally this function should exec '$(TARGET)-stubify' to generate 104 1.9 christos a stub, like gcc does. */ 105 1.1 christos 106 1.1 christos static void 107 1.9 christos go32exe_create_stub (bfd *abfd) 108 1.1 christos { 109 1.1 christos /* Do it only once. */ 110 1.9 christos if (coff_data (abfd)->stub == NULL) 111 1.1 christos { 112 1.1 christos char *stub; 113 1.1 christos struct stat st; 114 1.1 christos int f; 115 1.1 christos unsigned char header[10]; 116 1.1 christos char magic[8]; 117 1.1 christos unsigned long coff_start; 118 1.1 christos long exe_start; 119 1.1 christos 120 1.9 christos /* If we read a stub from an input file, use that one. */ 121 1.9 christos if (go32exe_temp_stub != NULL) 122 1.9 christos { 123 1.9 christos coff_data (abfd)->stub = bfd_alloc (abfd, 124 1.9 christos go32exe_temp_stub_size); 125 1.9 christos if (coff_data (abfd)->stub == NULL) 126 1.9 christos return; 127 1.9 christos memcpy (coff_data (abfd)->stub, go32exe_temp_stub, 128 1.9 christos go32exe_temp_stub_size); 129 1.9 christos coff_data (abfd)->stub_size = go32exe_temp_stub_size; 130 1.9 christos free (go32exe_temp_stub); 131 1.9 christos go32exe_temp_stub = NULL; 132 1.9 christos go32exe_temp_stub_size = 0; 133 1.9 christos return; 134 1.9 christos } 135 1.9 christos 136 1.1 christos /* Check at first the environment variable $(GO32STUB). */ 137 1.1 christos stub = getenv ("GO32STUB"); 138 1.1 christos /* Now check the environment variable $(STUB). */ 139 1.1 christos if (stub == NULL) 140 1.1 christos stub = getenv ("STUB"); 141 1.1 christos if (stub == NULL) 142 1.1 christos goto stub_end; 143 1.1 christos if (stat (stub, &st) != 0) 144 1.1 christos goto stub_end; 145 1.1 christos #ifdef O_BINARY 146 1.1 christos f = open (stub, O_RDONLY | O_BINARY); 147 1.1 christos #else 148 1.1 christos f = open (stub, O_RDONLY); 149 1.1 christos #endif 150 1.1 christos if (f < 0) 151 1.1 christos goto stub_end; 152 1.1 christos if (read (f, &header, sizeof (header)) < 0) 153 1.1 christos { 154 1.1 christos close (f); 155 1.1 christos goto stub_end; 156 1.1 christos } 157 1.1 christos if (_H (0) != 0x5a4d) /* It is not an exe file. */ 158 1.1 christos { 159 1.1 christos close (f); 160 1.1 christos goto stub_end; 161 1.1 christos } 162 1.1 christos /* Compute the size of the stub (it is every thing up 163 1.8 christos to the beginning of the coff image). */ 164 1.1 christos coff_start = (long) _H (2) * 512L; 165 1.1 christos if (_H (1)) 166 1.1 christos coff_start += (long) _H (1) - 512L; 167 1.1 christos 168 1.1 christos exe_start = _H (4) * 16; 169 1.1 christos if ((long) lseek (f, exe_start, SEEK_SET) != exe_start) 170 1.1 christos { 171 1.1 christos close (f); 172 1.1 christos goto stub_end; 173 1.1 christos } 174 1.1 christos if (read (f, &magic, 8) != 8) 175 1.1 christos { 176 1.1 christos close (f); 177 1.1 christos goto stub_end; 178 1.1 christos } 179 1.10 christos if (! startswith (magic, "go32stub")) 180 1.1 christos { 181 1.1 christos close (f); 182 1.1 christos goto stub_end; 183 1.1 christos } 184 1.1 christos /* Now we found a correct stub (hopefully). */ 185 1.9 christos coff_data (abfd)->stub = bfd_alloc (abfd, (bfd_size_type) coff_start); 186 1.9 christos if (coff_data (abfd)->stub == NULL) 187 1.1 christos { 188 1.1 christos close (f); 189 1.1 christos return; 190 1.1 christos } 191 1.1 christos lseek (f, 0L, SEEK_SET); 192 1.9 christos if ((unsigned long) read (f, coff_data (abfd)->stub, coff_start) 193 1.1 christos != coff_start) 194 1.1 christos { 195 1.9 christos bfd_release (abfd, coff_data (abfd)->stub); 196 1.9 christos coff_data (abfd)->stub = NULL; 197 1.1 christos } 198 1.9 christos else 199 1.9 christos coff_data (abfd)->stub_size = coff_start; 200 1.1 christos close (f); 201 1.1 christos } 202 1.9 christos stub_end: 203 1.1 christos /* There was something wrong above, so use now the standard builtin 204 1.1 christos stub. */ 205 1.9 christos if (coff_data (abfd)->stub == NULL) 206 1.1 christos { 207 1.9 christos coff_data (abfd)->stub 208 1.9 christos = bfd_alloc (abfd, (bfd_size_type) GO32EXE_DEFAULT_STUB_SIZE); 209 1.9 christos if (coff_data (abfd)->stub == NULL) 210 1.1 christos return; 211 1.9 christos memcpy (coff_data (abfd)->stub, go32exe_default_stub, 212 1.9 christos GO32EXE_DEFAULT_STUB_SIZE); 213 1.9 christos coff_data (abfd)->stub_size = GO32EXE_DEFAULT_STUB_SIZE; 214 1.1 christos } 215 1.1 christos } 216 1.1 christos 217 1.1 christos /* If ibfd was a stubbed coff image, copy the stub from that bfd 218 1.1 christos to the new obfd. */ 219 1.1 christos 220 1.10 christos static bool 221 1.9 christos go32exe_copy_private_bfd_data (bfd *ibfd, bfd *obfd) 222 1.1 christos { 223 1.1 christos /* Check if both are the same targets. */ 224 1.1 christos if (ibfd->xvec != obfd->xvec) 225 1.10 christos return true; 226 1.1 christos 227 1.9 christos /* Make sure we have a source stub. */ 228 1.9 christos BFD_ASSERT (coff_data (ibfd)->stub != NULL); 229 1.1 christos 230 1.9 christos /* Reallocate the output stub if necessary. */ 231 1.9 christos if (coff_data (ibfd)->stub_size > coff_data (obfd)->stub_size) 232 1.9 christos coff_data (obfd)->stub = bfd_alloc (obfd, coff_data (ibfd)->stub_size); 233 1.9 christos if (coff_data (obfd)->stub == NULL) 234 1.10 christos return false; 235 1.1 christos 236 1.1 christos /* Now copy the stub. */ 237 1.9 christos memcpy (coff_data (obfd)->stub, coff_data (ibfd)->stub, 238 1.9 christos coff_data (ibfd)->stub_size); 239 1.9 christos coff_data (obfd)->stub_size = coff_data (ibfd)->stub_size; 240 1.9 christos obfd->origin = coff_data (obfd)->stub_size; 241 1.1 christos 242 1.10 christos return true; 243 1.1 christos } 244 1.1 christos 245 1.9 christos /* Cleanup function, returned from check_format hook. */ 246 1.1 christos 247 1.9 christos static void 248 1.9 christos go32exe_cleanup (bfd *abfd) 249 1.1 christos { 250 1.9 christos abfd->origin = 0; 251 1.11 christos coff_object_cleanup (abfd); 252 1.9 christos 253 1.9 christos free (go32exe_temp_stub); 254 1.9 christos go32exe_temp_stub = NULL; 255 1.9 christos go32exe_temp_stub_size = 0; 256 1.9 christos } 257 1.1 christos 258 1.9 christos /* Check that there is a GO32 stub and read it to go32exe_temp_stub. 259 1.9 christos Then set abfd->origin so that the COFF image is read at the correct 260 1.9 christos file offset. */ 261 1.9 christos 262 1.9 christos static bfd_cleanup 263 1.9 christos go32exe_check_format (bfd *abfd) 264 1.9 christos { 265 1.9 christos struct external_DOS_hdr filehdr_dos; 266 1.9 christos uint16_t num_pages; 267 1.9 christos uint16_t last_page_size; 268 1.9 christos uint32_t header_end; 269 1.9 christos bfd_size_type stubsize; 270 1.9 christos 271 1.9 christos /* This format can not appear in an archive. */ 272 1.9 christos if (abfd->origin != 0) 273 1.1 christos { 274 1.1 christos bfd_set_error (bfd_error_wrong_format); 275 1.1 christos return NULL; 276 1.1 christos } 277 1.1 christos 278 1.9 christos bfd_set_error (bfd_error_system_call); 279 1.9 christos 280 1.9 christos /* Read in the stub file header, which is a DOS MZ executable. */ 281 1.11 christos if (bfd_read (&filehdr_dos, DOS_HDR_SIZE, abfd) != DOS_HDR_SIZE) 282 1.9 christos goto fail; 283 1.9 christos 284 1.9 christos /* Make sure that this is an MZ executable. */ 285 1.9 christos if (H_GET_16 (abfd, filehdr_dos.e_magic) != IMAGE_DOS_SIGNATURE) 286 1.9 christos goto fail_format; 287 1.9 christos 288 1.9 christos /* Determine the size of the stub */ 289 1.9 christos num_pages = H_GET_16 (abfd, filehdr_dos.e_cp); 290 1.9 christos last_page_size = H_GET_16 (abfd, filehdr_dos.e_cblp); 291 1.9 christos stubsize = num_pages * 512; 292 1.9 christos if (last_page_size != 0) 293 1.9 christos stubsize += last_page_size - 512; 294 1.9 christos 295 1.10 christos ufile_ptr filesize = bfd_get_file_size (abfd); 296 1.10 christos if (filesize != 0 && stubsize > filesize) 297 1.10 christos goto fail_format; 298 1.10 christos 299 1.9 christos /* Save now the stub to be used later. Put the stub data to a temporary 300 1.9 christos location first as tdata still does not exist. It may not even 301 1.9 christos be ever created if we are just checking the file format of ABFD. */ 302 1.11 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0) 303 1.11 christos goto fail; 304 1.9 christos go32exe_temp_stub = bfd_malloc (stubsize); 305 1.9 christos if (go32exe_temp_stub == NULL) 306 1.9 christos goto fail; 307 1.11 christos if (bfd_read (go32exe_temp_stub, stubsize, abfd) != stubsize) 308 1.9 christos goto fail; 309 1.9 christos go32exe_temp_stub_size = stubsize; 310 1.9 christos 311 1.9 christos /* Confirm that this is a go32stub. */ 312 1.9 christos header_end = H_GET_16 (abfd, filehdr_dos.e_cparhdr) * 16UL; 313 1.10 christos if (go32exe_temp_stub_size < header_end 314 1.10 christos || go32exe_temp_stub_size - header_end < sizeof "go32stub" - 1 315 1.10 christos || !startswith (go32exe_temp_stub + header_end, "go32stub")) 316 1.9 christos goto fail_format; 317 1.9 christos 318 1.9 christos /* Set origin to where the COFF header starts and seek there. */ 319 1.9 christos abfd->origin = stubsize; 320 1.1 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0) 321 1.9 christos goto fail; 322 1.9 christos 323 1.9 christos /* Call coff_object_p to read the COFF image. If this fails then the file 324 1.9 christos must be just a stub with no COFF data attached. */ 325 1.9 christos bfd_cleanup cleanup = coff_object_p (abfd); 326 1.9 christos if (cleanup == NULL) 327 1.9 christos goto fail; 328 1.11 christos BFD_ASSERT (cleanup == coff_object_cleanup); 329 1.9 christos 330 1.9 christos return go32exe_cleanup; 331 1.9 christos 332 1.9 christos fail_format: 333 1.9 christos bfd_set_error (bfd_error_wrong_format); 334 1.9 christos fail: 335 1.9 christos go32exe_cleanup (abfd); 336 1.9 christos return NULL; 337 1.9 christos } 338 1.9 christos 339 1.9 christos /* Write the stub to the output file, then call coff_write_object_contents. */ 340 1.9 christos 341 1.10 christos static bool 342 1.9 christos go32exe_write_object_contents (bfd *abfd) 343 1.9 christos { 344 1.9 christos const bfd_size_type pos = bfd_tell (abfd); 345 1.9 christos const bfd_size_type stubsize = coff_data (abfd)->stub_size; 346 1.9 christos 347 1.9 christos BFD_ASSERT (stubsize != 0); 348 1.9 christos 349 1.9 christos bfd_set_error (bfd_error_system_call); 350 1.1 christos 351 1.9 christos /* Write the stub. */ 352 1.9 christos abfd->origin = 0; 353 1.9 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0) 354 1.10 christos return false; 355 1.11 christos if (bfd_write (coff_data (abfd)->stub, stubsize, abfd) != stubsize) 356 1.10 christos return false; 357 1.9 christos 358 1.9 christos /* Seek back to where we were. */ 359 1.9 christos abfd->origin = stubsize; 360 1.9 christos if (bfd_seek (abfd, pos, SEEK_SET) != 0) 361 1.10 christos return false; 362 1.9 christos 363 1.9 christos return coff_write_object_contents (abfd); 364 1.9 christos } 365 1.9 christos 366 1.9 christos /* mkobject hook. Called directly through bfd_set_format or via 367 1.9 christos coff_mkobject_hook etc from bfd_check_format. */ 368 1.9 christos 369 1.10 christos static bool 370 1.9 christos go32exe_mkobject (bfd *abfd) 371 1.9 christos { 372 1.9 christos /* Don't output to an archive. */ 373 1.9 christos if (abfd->my_archive != NULL) 374 1.10 christos return false; 375 1.9 christos 376 1.9 christos if (!_bfd_go32_mkobject (abfd)) 377 1.10 christos return false; 378 1.9 christos 379 1.9 christos go32exe_create_stub (abfd); 380 1.9 christos if (coff_data (abfd)->stub == NULL) 381 1.9 christos { 382 1.9 christos bfd_release (abfd, coff_data (abfd)); 383 1.10 christos return false; 384 1.9 christos } 385 1.9 christos abfd->origin = coff_data (abfd)->stub_size; 386 1.9 christos 387 1.10 christos return true; 388 1.1 christos } 389