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