coff-stgo32.c revision 1.1 1 1.1 christos /* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
2 1.1 christos Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2007, 2009,
3 1.1 christos 2011, 2012 Free Software Foundation, Inc.
4 1.1 christos Written by Robert Hoehne.
5 1.1 christos
6 1.1 christos This file is part of BFD, the Binary File Descriptor library.
7 1.1 christos
8 1.1 christos This program is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3 of the License, or
11 1.1 christos (at your option) any later version.
12 1.1 christos
13 1.1 christos This program is distributed in the hope that it will be useful,
14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 christos GNU General Public License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program; if not, write to the Free Software
20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 1.1 christos MA 02110-1301, USA. */
22 1.1 christos
23 1.1 christos /* This file handles now also stubbed coff images. The stub is a small
24 1.1 christos DOS executable program before the coff image to load it in memory
25 1.1 christos and execute it. This is needed, because DOS cannot run coff files.
26 1.1 christos
27 1.1 christos All the functions below are called by the corresponding functions
28 1.1 christos from coffswap.h.
29 1.1 christos The only thing what they do is to adjust the information stored in
30 1.1 christos the COFF file which are offset into the file.
31 1.1 christos This is needed, because DJGPP uses a very special way to load and run
32 1.1 christos the coff image. It loads the image in memory and assumes then, that the
33 1.1 christos image had no stub by using the filepointers as pointers in the coff
34 1.1 christos image and NOT in the file.
35 1.1 christos
36 1.1 christos To be compatible with any existing executables I have fixed this
37 1.1 christos here and NOT in the DJGPP startup code. */
38 1.1 christos
39 1.1 christos #define TARGET_SYM go32stubbedcoff_vec
40 1.1 christos #define TARGET_NAME "coff-go32-exe"
41 1.1 christos #define TARGET_UNDERSCORE '_'
42 1.1 christos #define COFF_GO32_EXE
43 1.1 christos #define COFF_LONG_SECTION_NAMES
44 1.1 christos #define COFF_SUPPORT_GNU_LINKONCE
45 1.1 christos #define COFF_LONG_FILENAMES
46 1.1 christos
47 1.1 christos #define COFF_SECTION_ALIGNMENT_ENTRIES \
48 1.1 christos { COFF_SECTION_NAME_EXACT_MATCH (".data"), \
49 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
50 1.1 christos { COFF_SECTION_NAME_EXACT_MATCH (".text"), \
51 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
52 1.1 christos { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
53 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
54 1.1 christos { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \
55 1.1 christos COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
56 1.1 christos
57 1.1 christos #include "sysdep.h"
58 1.1 christos #include "bfd.h"
59 1.1 christos
60 1.1 christos /* All that ..._PRE and ...POST functions are called from the corresponding
61 1.1 christos coff_swap... functions. The ...PRE functions are called at the beginning
62 1.1 christos of the function and the ...POST functions at the end of the swap routines. */
63 1.1 christos
64 1.1 christos static void
65 1.1 christos adjust_filehdr_in_post (bfd *, void *, void *);
66 1.1 christos static void
67 1.1 christos adjust_filehdr_out_pre (bfd *, void *, void *);
68 1.1 christos static void
69 1.1 christos adjust_filehdr_out_post (bfd *, void *, void *);
70 1.1 christos static void
71 1.1 christos adjust_scnhdr_in_post (bfd *, void *, void *);
72 1.1 christos static void
73 1.1 christos adjust_scnhdr_out_pre (bfd *, void *, void *);
74 1.1 christos static void
75 1.1 christos adjust_scnhdr_out_post (bfd *, void *, void *);
76 1.1 christos static void
77 1.1 christos adjust_aux_in_post (bfd *, void *, int, int, int, int, void *);
78 1.1 christos static void
79 1.1 christos adjust_aux_out_pre (bfd *, void *, int, int, int, int, void *);
80 1.1 christos static void
81 1.1 christos adjust_aux_out_post (bfd *, void *, int, int, int, int, void *);
82 1.1 christos static void
83 1.1 christos create_go32_stub (bfd *);
84 1.1 christos
85 1.1 christos #define COFF_ADJUST_FILEHDR_IN_POST adjust_filehdr_in_post
86 1.1 christos #define COFF_ADJUST_FILEHDR_OUT_PRE adjust_filehdr_out_pre
87 1.1 christos #define COFF_ADJUST_FILEHDR_OUT_POST adjust_filehdr_out_post
88 1.1 christos
89 1.1 christos #define COFF_ADJUST_SCNHDR_IN_POST adjust_scnhdr_in_post
90 1.1 christos #define COFF_ADJUST_SCNHDR_OUT_PRE adjust_scnhdr_out_pre
91 1.1 christos #define COFF_ADJUST_SCNHDR_OUT_POST adjust_scnhdr_out_post
92 1.1 christos
93 1.1 christos #define COFF_ADJUST_AUX_IN_POST adjust_aux_in_post
94 1.1 christos #define COFF_ADJUST_AUX_OUT_PRE adjust_aux_out_pre
95 1.1 christos #define COFF_ADJUST_AUX_OUT_POST adjust_aux_out_post
96 1.1 christos
97 1.1 christos static const bfd_target *go32_check_format (bfd *);
98 1.1 christos
99 1.1 christos #define COFF_CHECK_FORMAT go32_check_format
100 1.1 christos
101 1.1 christos static bfd_boolean
102 1.1 christos go32_stubbed_coff_bfd_copy_private_bfd_data (bfd *, bfd *);
103 1.1 christos
104 1.1 christos #define coff_bfd_copy_private_bfd_data go32_stubbed_coff_bfd_copy_private_bfd_data
105 1.1 christos
106 1.1 christos #include "coff-i386.c"
107 1.1 christos
108 1.1 christos /* This macro is used, because I cannot assume the endianness of the
109 1.1 christos host system. */
110 1.1 christos #define _H(index) (H_GET_16 (abfd, (header + index * 2)))
111 1.1 christos
112 1.1 christos /* These bytes are a 2048-byte DOS executable, which loads the COFF
113 1.1 christos image into memory and then runs it. It is called 'stub'. */
114 1.1 christos
115 1.1 christos static const unsigned char stub_bytes[GO32_STUBSIZE] =
116 1.1 christos {
117 1.1 christos #include "go32stub.h"
118 1.1 christos };
119 1.1 christos
120 1.1 christos /*
121 1.1 christos I have not commented each swap function below, because the
122 1.1 christos technique is in any function the same. For the ...in function,
123 1.1 christos all the pointers are adjusted by adding GO32_STUBSIZE and for the
124 1.1 christos ...out function, it is subtracted first and after calling the
125 1.1 christos standard swap function it is reset to the old value. */
126 1.1 christos
127 1.1 christos /* This macro is used for adjusting the filepointers, which
128 1.1 christos is done only, if the pointer is nonzero. */
129 1.1 christos
130 1.1 christos #define ADJUST_VAL(val,diff) \
131 1.1 christos if (val != 0) val += diff
132 1.1 christos
133 1.1 christos static void
134 1.1 christos adjust_filehdr_in_post (bfd * abfd ATTRIBUTE_UNUSED,
135 1.1 christos void * src,
136 1.1 christos void * dst)
137 1.1 christos {
138 1.1 christos FILHDR *filehdr_src = (FILHDR *) src;
139 1.1 christos struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
140 1.1 christos
141 1.1 christos ADJUST_VAL (filehdr_dst->f_symptr, GO32_STUBSIZE);
142 1.1 christos
143 1.1 christos /* Save now the stub to be used later. Put the stub data to FILEHDR_DST
144 1.1 christos first as coff_data (abfd) still does not exist. It may not even be ever
145 1.1 christos created as we are just checking the file format of ABFD. */
146 1.1 christos memcpy (filehdr_dst->go32stub, filehdr_src->stub, GO32_STUBSIZE);
147 1.1 christos filehdr_dst->f_flags |= F_GO32STUB;
148 1.1 christos }
149 1.1 christos
150 1.1 christos static void
151 1.1 christos adjust_filehdr_out_pre (bfd * abfd, void * in, void * out)
152 1.1 christos {
153 1.1 christos struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
154 1.1 christos FILHDR *filehdr_out = (FILHDR *) out;
155 1.1 christos
156 1.1 christos /* Generate the stub. */
157 1.1 christos create_go32_stub (abfd);
158 1.1 christos
159 1.1 christos /* Copy the stub to the file header. */
160 1.1 christos if (coff_data (abfd)->go32stub != NULL)
161 1.1 christos memcpy (filehdr_out->stub, coff_data (abfd)->go32stub, GO32_STUBSIZE);
162 1.1 christos else
163 1.1 christos /* Use the default. */
164 1.1 christos memcpy (filehdr_out->stub, stub_bytes, GO32_STUBSIZE);
165 1.1 christos
166 1.1 christos ADJUST_VAL (filehdr_in->f_symptr, -GO32_STUBSIZE);
167 1.1 christos }
168 1.1 christos
169 1.1 christos static void
170 1.1 christos adjust_filehdr_out_post (bfd * abfd ATTRIBUTE_UNUSED,
171 1.1 christos void * in,
172 1.1 christos void * out ATTRIBUTE_UNUSED)
173 1.1 christos {
174 1.1 christos struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
175 1.1 christos /* Undo the above change. */
176 1.1 christos ADJUST_VAL (filehdr_in->f_symptr, GO32_STUBSIZE);
177 1.1 christos }
178 1.1 christos
179 1.1 christos static void
180 1.1 christos adjust_scnhdr_in_post (bfd * abfd ATTRIBUTE_UNUSED,
181 1.1 christos void * ext ATTRIBUTE_UNUSED,
182 1.1 christos void * in)
183 1.1 christos {
184 1.1 christos struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
185 1.1 christos
186 1.1 christos ADJUST_VAL (scnhdr_int->s_scnptr, GO32_STUBSIZE);
187 1.1 christos ADJUST_VAL (scnhdr_int->s_relptr, GO32_STUBSIZE);
188 1.1 christos ADJUST_VAL (scnhdr_int->s_lnnoptr, GO32_STUBSIZE);
189 1.1 christos }
190 1.1 christos
191 1.1 christos static void
192 1.1 christos adjust_scnhdr_out_pre (bfd * abfd ATTRIBUTE_UNUSED,
193 1.1 christos void * in,
194 1.1 christos void * out ATTRIBUTE_UNUSED)
195 1.1 christos {
196 1.1 christos struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
197 1.1 christos
198 1.1 christos ADJUST_VAL (scnhdr_int->s_scnptr, -GO32_STUBSIZE);
199 1.1 christos ADJUST_VAL (scnhdr_int->s_relptr, -GO32_STUBSIZE);
200 1.1 christos ADJUST_VAL (scnhdr_int->s_lnnoptr, -GO32_STUBSIZE);
201 1.1 christos }
202 1.1 christos
203 1.1 christos static void
204 1.1 christos adjust_scnhdr_out_post (bfd * abfd ATTRIBUTE_UNUSED,
205 1.1 christos void * in,
206 1.1 christos void * out ATTRIBUTE_UNUSED)
207 1.1 christos {
208 1.1 christos struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
209 1.1 christos
210 1.1 christos ADJUST_VAL (scnhdr_int->s_scnptr, GO32_STUBSIZE);
211 1.1 christos ADJUST_VAL (scnhdr_int->s_relptr, GO32_STUBSIZE);
212 1.1 christos ADJUST_VAL (scnhdr_int->s_lnnoptr, GO32_STUBSIZE);
213 1.1 christos }
214 1.1 christos
215 1.1 christos static void
216 1.1 christos adjust_aux_in_post (bfd * abfd ATTRIBUTE_UNUSED,
217 1.1 christos void * ext1 ATTRIBUTE_UNUSED,
218 1.1 christos int type,
219 1.1 christos int in_class,
220 1.1 christos int indx ATTRIBUTE_UNUSED,
221 1.1 christos int numaux ATTRIBUTE_UNUSED,
222 1.1 christos void * in1)
223 1.1 christos {
224 1.1 christos union internal_auxent *in = (union internal_auxent *) in1;
225 1.1 christos
226 1.1 christos if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
227 1.1 christos || ISTAG (in_class))
228 1.1 christos {
229 1.1 christos ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, GO32_STUBSIZE);
230 1.1 christos }
231 1.1 christos }
232 1.1 christos
233 1.1 christos static void
234 1.1 christos adjust_aux_out_pre (bfd *abfd ATTRIBUTE_UNUSED,
235 1.1 christos void * inp,
236 1.1 christos int type,
237 1.1 christos int in_class,
238 1.1 christos int indx ATTRIBUTE_UNUSED,
239 1.1 christos int numaux ATTRIBUTE_UNUSED,
240 1.1 christos void * extp ATTRIBUTE_UNUSED)
241 1.1 christos {
242 1.1 christos union internal_auxent *in = (union internal_auxent *) inp;
243 1.1 christos
244 1.1 christos if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
245 1.1 christos || ISTAG (in_class))
246 1.1 christos {
247 1.1 christos ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, -GO32_STUBSIZE);
248 1.1 christos }
249 1.1 christos }
250 1.1 christos
251 1.1 christos static void
252 1.1 christos adjust_aux_out_post (bfd *abfd ATTRIBUTE_UNUSED,
253 1.1 christos void * inp,
254 1.1 christos int type,
255 1.1 christos int in_class,
256 1.1 christos int indx ATTRIBUTE_UNUSED,
257 1.1 christos int numaux ATTRIBUTE_UNUSED,
258 1.1 christos void * extp ATTRIBUTE_UNUSED)
259 1.1 christos {
260 1.1 christos union internal_auxent *in = (union internal_auxent *) inp;
261 1.1 christos
262 1.1 christos if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
263 1.1 christos || ISTAG (in_class))
264 1.1 christos {
265 1.1 christos ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, GO32_STUBSIZE);
266 1.1 christos }
267 1.1 christos }
268 1.1 christos
269 1.1 christos /* That's the function, which creates the stub. There are
270 1.1 christos different cases from where the stub is taken.
271 1.1 christos At first the environment variable $(GO32STUB) is checked and then
272 1.1 christos $(STUB) if it was not set.
273 1.1 christos If it exists and points to a valid stub the stub is taken from
274 1.1 christos that file. This file can be also a whole executable file, because
275 1.1 christos the stub is computed from the exe information at the start of that
276 1.1 christos file.
277 1.1 christos
278 1.1 christos If there was any error, the standard stub (compiled in this file)
279 1.1 christos is taken. */
280 1.1 christos
281 1.1 christos static void
282 1.1 christos create_go32_stub (bfd *abfd)
283 1.1 christos {
284 1.1 christos /* Do it only once. */
285 1.1 christos if (coff_data (abfd)->go32stub == NULL)
286 1.1 christos {
287 1.1 christos char *stub;
288 1.1 christos struct stat st;
289 1.1 christos int f;
290 1.1 christos unsigned char header[10];
291 1.1 christos char magic[8];
292 1.1 christos unsigned long coff_start;
293 1.1 christos long exe_start;
294 1.1 christos
295 1.1 christos /* Check at first the environment variable $(GO32STUB). */
296 1.1 christos stub = getenv ("GO32STUB");
297 1.1 christos /* Now check the environment variable $(STUB). */
298 1.1 christos if (stub == NULL)
299 1.1 christos stub = getenv ("STUB");
300 1.1 christos if (stub == NULL)
301 1.1 christos goto stub_end;
302 1.1 christos if (stat (stub, &st) != 0)
303 1.1 christos goto stub_end;
304 1.1 christos #ifdef O_BINARY
305 1.1 christos f = open (stub, O_RDONLY | O_BINARY);
306 1.1 christos #else
307 1.1 christos f = open (stub, O_RDONLY);
308 1.1 christos #endif
309 1.1 christos if (f < 0)
310 1.1 christos goto stub_end;
311 1.1 christos if (read (f, &header, sizeof (header)) < 0)
312 1.1 christos {
313 1.1 christos close (f);
314 1.1 christos goto stub_end;
315 1.1 christos }
316 1.1 christos if (_H (0) != 0x5a4d) /* It is not an exe file. */
317 1.1 christos {
318 1.1 christos close (f);
319 1.1 christos goto stub_end;
320 1.1 christos }
321 1.1 christos /* Compute the size of the stub (it is every thing up
322 1.1 christos to the beginning of the coff image). */
323 1.1 christos coff_start = (long) _H (2) * 512L;
324 1.1 christos if (_H (1))
325 1.1 christos coff_start += (long) _H (1) - 512L;
326 1.1 christos
327 1.1 christos /* Currently there is only a fixed stub size of 2048 bytes
328 1.1 christos supported. */
329 1.1 christos if (coff_start != 2048)
330 1.1 christos {
331 1.1 christos close (f);
332 1.1 christos goto stub_end;
333 1.1 christos }
334 1.1 christos exe_start = _H (4) * 16;
335 1.1 christos if ((long) lseek (f, exe_start, SEEK_SET) != exe_start)
336 1.1 christos {
337 1.1 christos close (f);
338 1.1 christos goto stub_end;
339 1.1 christos }
340 1.1 christos if (read (f, &magic, 8) != 8)
341 1.1 christos {
342 1.1 christos close (f);
343 1.1 christos goto stub_end;
344 1.1 christos }
345 1.1 christos if (! CONST_STRNEQ (magic, "go32stub"))
346 1.1 christos {
347 1.1 christos close (f);
348 1.1 christos goto stub_end;
349 1.1 christos }
350 1.1 christos /* Now we found a correct stub (hopefully). */
351 1.1 christos coff_data (abfd)->go32stub = bfd_alloc (abfd, (bfd_size_type) coff_start);
352 1.1 christos if (coff_data (abfd)->go32stub == NULL)
353 1.1 christos {
354 1.1 christos close (f);
355 1.1 christos return;
356 1.1 christos }
357 1.1 christos lseek (f, 0L, SEEK_SET);
358 1.1 christos if ((unsigned long) read (f, coff_data (abfd)->go32stub, coff_start)
359 1.1 christos != coff_start)
360 1.1 christos {
361 1.1 christos bfd_release (abfd, coff_data (abfd)->go32stub);
362 1.1 christos coff_data (abfd)->go32stub = NULL;
363 1.1 christos }
364 1.1 christos close (f);
365 1.1 christos }
366 1.1 christos stub_end:
367 1.1 christos /* There was something wrong above, so use now the standard builtin
368 1.1 christos stub. */
369 1.1 christos if (coff_data (abfd)->go32stub == NULL)
370 1.1 christos {
371 1.1 christos coff_data (abfd)->go32stub
372 1.1 christos = bfd_alloc (abfd, (bfd_size_type) GO32_STUBSIZE);
373 1.1 christos if (coff_data (abfd)->go32stub == NULL)
374 1.1 christos return;
375 1.1 christos memcpy (coff_data (abfd)->go32stub, stub_bytes, GO32_STUBSIZE);
376 1.1 christos }
377 1.1 christos }
378 1.1 christos
379 1.1 christos /* If ibfd was a stubbed coff image, copy the stub from that bfd
380 1.1 christos to the new obfd. */
381 1.1 christos
382 1.1 christos static bfd_boolean
383 1.1 christos go32_stubbed_coff_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
384 1.1 christos {
385 1.1 christos /* Check if both are the same targets. */
386 1.1 christos if (ibfd->xvec != obfd->xvec)
387 1.1 christos return TRUE;
388 1.1 christos
389 1.1 christos /* Check if we have a source stub. */
390 1.1 christos if (coff_data (ibfd)->go32stub == NULL)
391 1.1 christos return TRUE;
392 1.1 christos
393 1.1 christos /* As adjust_filehdr_out_pre may get called only after this function,
394 1.1 christos optionally allocate the output stub. */
395 1.1 christos if (coff_data (obfd)->go32stub == NULL)
396 1.1 christos coff_data (obfd)->go32stub = bfd_alloc (obfd,
397 1.1 christos (bfd_size_type) GO32_STUBSIZE);
398 1.1 christos
399 1.1 christos /* Now copy the stub. */
400 1.1 christos if (coff_data (obfd)->go32stub != NULL)
401 1.1 christos memcpy (coff_data (obfd)->go32stub, coff_data (ibfd)->go32stub,
402 1.1 christos GO32_STUBSIZE);
403 1.1 christos
404 1.1 christos return TRUE;
405 1.1 christos }
406 1.1 christos
407 1.1 christos /* coff_object_p only checks 2 bytes F_MAGIC at GO32_STUBSIZE inside the file
408 1.1 christos which is too fragile. */
409 1.1 christos
410 1.1 christos static const bfd_target *
411 1.1 christos go32_check_format (bfd *abfd)
412 1.1 christos {
413 1.1 christos char mz[2];
414 1.1 christos
415 1.1 christos if (bfd_bread (mz, 2, abfd) != 2 || mz[0] != 'M' || mz[1] != 'Z')
416 1.1 christos {
417 1.1 christos bfd_set_error (bfd_error_wrong_format);
418 1.1 christos return NULL;
419 1.1 christos }
420 1.1 christos
421 1.1 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0)
422 1.1 christos return NULL;
423 1.1 christos
424 1.1 christos return coff_object_p (abfd);
425 1.1 christos }
426