coff-stgo32.c revision 1.10 1 1.1 christos /* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
2 1.10 christos Copyright (C) 1997-2022 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.9 christos
252 1.9 christos free (go32exe_temp_stub);
253 1.9 christos go32exe_temp_stub = NULL;
254 1.9 christos go32exe_temp_stub_size = 0;
255 1.9 christos }
256 1.1 christos
257 1.9 christos /* Check that there is a GO32 stub and read it to go32exe_temp_stub.
258 1.9 christos Then set abfd->origin so that the COFF image is read at the correct
259 1.9 christos file offset. */
260 1.9 christos
261 1.9 christos static bfd_cleanup
262 1.9 christos go32exe_check_format (bfd *abfd)
263 1.9 christos {
264 1.9 christos struct external_DOS_hdr filehdr_dos;
265 1.9 christos uint16_t num_pages;
266 1.9 christos uint16_t last_page_size;
267 1.9 christos uint32_t header_end;
268 1.9 christos bfd_size_type stubsize;
269 1.9 christos
270 1.9 christos /* This format can not appear in an archive. */
271 1.9 christos if (abfd->origin != 0)
272 1.1 christos {
273 1.1 christos bfd_set_error (bfd_error_wrong_format);
274 1.1 christos return NULL;
275 1.1 christos }
276 1.1 christos
277 1.9 christos bfd_set_error (bfd_error_system_call);
278 1.9 christos
279 1.9 christos /* Read in the stub file header, which is a DOS MZ executable. */
280 1.9 christos if (bfd_bread (&filehdr_dos, DOS_HDR_SIZE, abfd) != DOS_HDR_SIZE)
281 1.9 christos goto fail;
282 1.9 christos
283 1.9 christos /* Make sure that this is an MZ executable. */
284 1.9 christos if (H_GET_16 (abfd, filehdr_dos.e_magic) != IMAGE_DOS_SIGNATURE)
285 1.9 christos goto fail_format;
286 1.9 christos
287 1.9 christos /* Determine the size of the stub */
288 1.9 christos num_pages = H_GET_16 (abfd, filehdr_dos.e_cp);
289 1.9 christos last_page_size = H_GET_16 (abfd, filehdr_dos.e_cblp);
290 1.9 christos stubsize = num_pages * 512;
291 1.9 christos if (last_page_size != 0)
292 1.9 christos stubsize += last_page_size - 512;
293 1.9 christos
294 1.10 christos ufile_ptr filesize = bfd_get_file_size (abfd);
295 1.10 christos if (filesize != 0 && stubsize > filesize)
296 1.10 christos goto fail_format;
297 1.10 christos
298 1.9 christos /* Save now the stub to be used later. Put the stub data to a temporary
299 1.9 christos location first as tdata still does not exist. It may not even
300 1.9 christos be ever created if we are just checking the file format of ABFD. */
301 1.9 christos bfd_seek (abfd, 0, SEEK_SET);
302 1.9 christos go32exe_temp_stub = bfd_malloc (stubsize);
303 1.9 christos if (go32exe_temp_stub == NULL)
304 1.9 christos goto fail;
305 1.9 christos if (bfd_bread (go32exe_temp_stub, stubsize, abfd) != stubsize)
306 1.9 christos goto fail;
307 1.9 christos go32exe_temp_stub_size = stubsize;
308 1.9 christos
309 1.9 christos /* Confirm that this is a go32stub. */
310 1.9 christos header_end = H_GET_16 (abfd, filehdr_dos.e_cparhdr) * 16UL;
311 1.10 christos if (go32exe_temp_stub_size < header_end
312 1.10 christos || go32exe_temp_stub_size - header_end < sizeof "go32stub" - 1
313 1.10 christos || !startswith (go32exe_temp_stub + header_end, "go32stub"))
314 1.9 christos goto fail_format;
315 1.9 christos
316 1.9 christos /* Set origin to where the COFF header starts and seek there. */
317 1.9 christos abfd->origin = stubsize;
318 1.1 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0)
319 1.9 christos goto fail;
320 1.9 christos
321 1.9 christos /* Call coff_object_p to read the COFF image. If this fails then the file
322 1.9 christos must be just a stub with no COFF data attached. */
323 1.9 christos bfd_cleanup cleanup = coff_object_p (abfd);
324 1.9 christos if (cleanup == NULL)
325 1.9 christos goto fail;
326 1.9 christos BFD_ASSERT (cleanup == _bfd_no_cleanup);
327 1.9 christos
328 1.9 christos return go32exe_cleanup;
329 1.9 christos
330 1.9 christos fail_format:
331 1.9 christos bfd_set_error (bfd_error_wrong_format);
332 1.9 christos fail:
333 1.9 christos go32exe_cleanup (abfd);
334 1.9 christos return NULL;
335 1.9 christos }
336 1.9 christos
337 1.9 christos /* Write the stub to the output file, then call coff_write_object_contents. */
338 1.9 christos
339 1.10 christos static bool
340 1.9 christos go32exe_write_object_contents (bfd *abfd)
341 1.9 christos {
342 1.9 christos const bfd_size_type pos = bfd_tell (abfd);
343 1.9 christos const bfd_size_type stubsize = coff_data (abfd)->stub_size;
344 1.9 christos
345 1.9 christos BFD_ASSERT (stubsize != 0);
346 1.9 christos
347 1.9 christos bfd_set_error (bfd_error_system_call);
348 1.1 christos
349 1.9 christos /* Write the stub. */
350 1.9 christos abfd->origin = 0;
351 1.9 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0)
352 1.10 christos return false;
353 1.9 christos if (bfd_bwrite (coff_data (abfd)->stub, stubsize, abfd) != stubsize)
354 1.10 christos return false;
355 1.9 christos
356 1.9 christos /* Seek back to where we were. */
357 1.9 christos abfd->origin = stubsize;
358 1.9 christos if (bfd_seek (abfd, pos, SEEK_SET) != 0)
359 1.10 christos return false;
360 1.9 christos
361 1.9 christos return coff_write_object_contents (abfd);
362 1.9 christos }
363 1.9 christos
364 1.9 christos /* mkobject hook. Called directly through bfd_set_format or via
365 1.9 christos coff_mkobject_hook etc from bfd_check_format. */
366 1.9 christos
367 1.10 christos static bool
368 1.9 christos go32exe_mkobject (bfd *abfd)
369 1.9 christos {
370 1.9 christos /* Don't output to an archive. */
371 1.9 christos if (abfd->my_archive != NULL)
372 1.10 christos return false;
373 1.9 christos
374 1.9 christos if (!_bfd_go32_mkobject (abfd))
375 1.10 christos return false;
376 1.9 christos
377 1.9 christos go32exe_create_stub (abfd);
378 1.9 christos if (coff_data (abfd)->stub == NULL)
379 1.9 christos {
380 1.9 christos bfd_release (abfd, coff_data (abfd));
381 1.10 christos return false;
382 1.9 christos }
383 1.9 christos abfd->origin = coff_data (abfd)->stub_size;
384 1.9 christos
385 1.10 christos return true;
386 1.1 christos }
387