1 /* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
2 Copyright 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3 Written by Robert Hoehne.
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 /* This file handles now also stubbed coff images. The stub is a small
22 DOS executable program before the coff image to load it in memory
23 and execute it. This is needed, because DOS cannot run coff files.
25 All the functions below are called by the corresponding functions
27 The only thing what they do is to adjust the information stored in
28 the COFF file which are offset into the file.
29 This is needed, because DJGPP uses a very special way to load and run
30 the coff image. It loads the image in memory and assumes then, that the
31 image had no stub by using the filepointers as pointers in the coff
32 image and NOT in the file.
34 To be compatible with any existing executables I have fixed this
35 here and NOT in the DJGPP startup code.
38 #define TARGET_SYM go32stubbedcoff_vec
39 #define TARGET_NAME "coff-go32-exe"
40 #define TARGET_UNDERSCORE '_'
42 #define COFF_LONG_SECTION_NAMES
43 #define COFF_SUPPORT_GNU_LINKONCE
44 #define COFF_LONG_FILENAMES
46 #define COFF_SECTION_ALIGNMENT_ENTRIES \
47 { COFF_SECTION_NAME_EXACT_MATCH (".data"), \
48 COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
49 { COFF_SECTION_NAME_EXACT_MATCH (".text"), \
50 COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
51 { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
52 COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
56 /* At first the prototypes */
59 adjust_filehdr_in_post PARAMS ((bfd * abfd, PTR src, PTR dst));
61 adjust_filehdr_out_pre PARAMS ((bfd * abfd, PTR in, PTR out));
63 adjust_filehdr_out_post PARAMS ((bfd * abfd, PTR in, PTR out));
66 adjust_scnhdr_in_post PARAMS ((bfd * abfd, PTR ext, PTR in));
68 adjust_scnhdr_out_pre PARAMS ((bfd * abfd, PTR in, PTR out));
70 adjust_scnhdr_out_post PARAMS ((bfd * abfd, PTR in, PTR out));
73 adjust_aux_in_post PARAMS ((bfd * abfd, PTR ext1, int type, int class, int indx,
74 int numaux, PTR in1));
76 adjust_aux_out_pre PARAMS ((bfd * abfd, PTR inp, int type, int class, int indx,
77 int numaux, PTR extp));
79 adjust_aux_out_post PARAMS ((bfd * abfd, PTR inp, int type, int class, int indx,
80 int numaux, PTR extp));
83 create_go32_stub PARAMS ((bfd * abfd));
86 All that ..._PRE and ...POST functions are called from the corresponding
87 coff_swap... functions. The ...PRE functions are called at the beginning
88 of the function and the ...POST functions at the end of the swap routines.
91 #define COFF_ADJUST_FILEHDR_IN_POST adjust_filehdr_in_post
92 #define COFF_ADJUST_FILEHDR_OUT_PRE adjust_filehdr_out_pre
93 #define COFF_ADJUST_FILEHDR_OUT_POST adjust_filehdr_out_post
95 #define COFF_ADJUST_SCNHDR_IN_POST adjust_scnhdr_in_post
96 #define COFF_ADJUST_SCNHDR_OUT_PRE adjust_scnhdr_out_pre
97 #define COFF_ADJUST_SCNHDR_OUT_POST adjust_scnhdr_out_post
99 #define COFF_ADJUST_AUX_IN_POST adjust_aux_in_post
100 #define COFF_ADJUST_AUX_OUT_PRE adjust_aux_out_pre
101 #define COFF_ADJUST_AUX_OUT_POST adjust_aux_out_post
104 go32_stubbed_coff_bfd_copy_private_bfd_data PARAMS ((bfd * ibfd, bfd * obfd));
106 #define coff_bfd_copy_private_bfd_data go32_stubbed_coff_bfd_copy_private_bfd_data
108 #include "coff-i386.c"
110 /* I hold in the usrdata the stub */
111 #define bfd_coff_go32stub bfd_usrdata
113 /* This macro is used, because I cannot assume the endianess of the
115 #define _H(index) (bfd_h_get_16(abfd, (bfd_byte *) (header+index*2)))
117 /* These bytes are a 2048-byte DOS executable, which loads the COFF
118 image into memory and then runs it. It is called 'stub' */
120 static unsigned char stub_bytes[STUBSIZE] =
122 #include "go32stub.h"
126 I have not commented each swap function below, because the
127 technique is in any function the same. For the ...in function,
128 all the pointers are adjusted by adding STUBSIZE and for the
129 ...out function, it is subtracted first and after calling the
130 standard swap function it is reset to the old value */
132 /* This macro is used for adjusting the filepointers, which
133 is done only, if the pointer is nonzero */
135 #define ADJUST_VAL(val,diff) \
136 if (val != 0) val += diff
139 adjust_filehdr_in_post (abfd, src, dst)
144 FILHDR *filehdr_src = (FILHDR *) src;
145 struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
147 ADJUST_VAL (filehdr_dst->f_symptr, STUBSIZE);
149 /* Save now the stub to be used later */
150 bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, STUBSIZE);
152 /* Since this function returns no status, I do not set here
154 That means, before the use of bfd_coff_go32stub (), this value
155 should be checked if it is != NULL */
156 if (bfd_coff_go32stub (abfd) == NULL)
158 memcpy (bfd_coff_go32stub (abfd), filehdr_src->stub, STUBSIZE);
162 adjust_filehdr_out_pre (abfd, in, out)
167 struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
168 FILHDR *filehdr_out = (FILHDR *) out;
170 /* Generate the stub */
171 create_go32_stub (abfd);
173 /* Copy the stub to the file header */
174 if (bfd_coff_go32stub (abfd) != NULL)
175 memcpy (filehdr_out->stub, bfd_coff_go32stub (abfd), STUBSIZE);
177 /* use the default */
178 memcpy (filehdr_out->stub, stub_bytes, STUBSIZE);
180 ADJUST_VAL (filehdr_in->f_symptr, -STUBSIZE);
184 adjust_filehdr_out_post (abfd, in, out)
185 bfd *abfd ATTRIBUTE_UNUSED;
187 PTR out ATTRIBUTE_UNUSED;
189 struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
190 /* undo the above change */
191 ADJUST_VAL (filehdr_in->f_symptr, STUBSIZE);
195 adjust_scnhdr_in_post (abfd, ext, in)
196 bfd *abfd ATTRIBUTE_UNUSED;
197 PTR ext ATTRIBUTE_UNUSED;
200 struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
202 ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE);
203 ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE);
204 ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE);
208 adjust_scnhdr_out_pre (abfd, in, out)
209 bfd *abfd ATTRIBUTE_UNUSED;
211 PTR out ATTRIBUTE_UNUSED;
213 struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
215 ADJUST_VAL (scnhdr_int->s_scnptr, -STUBSIZE);
216 ADJUST_VAL (scnhdr_int->s_relptr, -STUBSIZE);
217 ADJUST_VAL (scnhdr_int->s_lnnoptr, -STUBSIZE);
221 adjust_scnhdr_out_post (abfd, in, out)
222 bfd *abfd ATTRIBUTE_UNUSED;
224 PTR out ATTRIBUTE_UNUSED;
226 struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
228 ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE);
229 ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE);
230 ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE);
234 adjust_aux_in_post (abfd, ext1, type, class, indx, numaux, in1)
235 bfd *abfd ATTRIBUTE_UNUSED;
236 PTR ext1 ATTRIBUTE_UNUSED;
239 int indx ATTRIBUTE_UNUSED;
240 int numaux ATTRIBUTE_UNUSED;
243 union internal_auxent *in = (union internal_auxent *) in1;
245 if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
247 ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE);
252 adjust_aux_out_pre (abfd, inp, type, class, indx, numaux, extp)
253 bfd *abfd ATTRIBUTE_UNUSED;
257 int indx ATTRIBUTE_UNUSED;
258 int numaux ATTRIBUTE_UNUSED;
259 PTR extp ATTRIBUTE_UNUSED;
261 union internal_auxent *in = (union internal_auxent *) inp;
263 if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
265 ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, -STUBSIZE);
270 adjust_aux_out_post (abfd, inp, type, class, indx, numaux, extp)
271 bfd *abfd ATTRIBUTE_UNUSED;
275 int indx ATTRIBUTE_UNUSED;
276 int numaux ATTRIBUTE_UNUSED;
277 PTR extp ATTRIBUTE_UNUSED;
279 union internal_auxent *in = (union internal_auxent *) inp;
281 if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
283 ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE);
288 That's the function, which creates the stub. There are
289 different cases from where the stub is taken.
290 At first the environment variable $(GO32STUB) is checked and then
291 $(STUB) if it was not set.
292 If it exists and points to a valid stub the stub is taken from
293 that file. This file can be also a whole executable file, because
294 the stub is computed from the exe information at the start of that
297 If there was any error, the standard stub (compiled in this file)
302 create_go32_stub (abfd)
305 /* Do it only once */
306 if (bfd_coff_go32stub (abfd) == NULL)
311 unsigned char header[10];
313 unsigned long coff_start, exe_start;
315 /* Check at first the environment variable $(GO32STUB) */
316 stub = getenv ("GO32STUB");
317 /* Now check the environment variable $(STUB) */
319 stub = getenv ("STUB");
322 if (stat (stub, &st) != 0)
325 f = open (stub, O_RDONLY | O_BINARY);
327 f = open (stub, O_RDONLY);
331 if (read (f, &header, sizeof (header)) < 0)
336 if (_H (0) != 0x5a4d) /* it is not an exe file */
341 /* Compute the size of the stub (it is every thing up
342 to the beginning of the coff image) */
343 coff_start = (long) _H (2) * 512L;
345 coff_start += (long) _H (1) - 512L;
347 /* Currently there is only a fixed stub size of 2048 bytes
349 if (coff_start != 2048)
354 exe_start = _H (4) * 16;
355 if ((unsigned long) lseek (f, exe_start, SEEK_SET) != exe_start)
360 if (read (f, &magic, 8) != 8)
365 if (memcmp (magic, "go32stub", 8) != 0)
370 /* Now we found a correct stub (hopefully) */
371 bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, coff_start);
372 if (bfd_coff_go32stub (abfd) == NULL)
377 lseek (f, 0L, SEEK_SET);
378 if ((unsigned long) read (f, bfd_coff_go32stub (abfd), coff_start)
381 bfd_release (abfd, bfd_coff_go32stub (abfd));
382 bfd_coff_go32stub (abfd) = NULL;
387 /* There was something wrong above, so use now the standard builtin
389 if (bfd_coff_go32stub (abfd) == NULL)
391 bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, STUBSIZE);
392 if (bfd_coff_go32stub (abfd) == NULL)
397 memcpy (bfd_coff_go32stub (abfd), stub_bytes, STUBSIZE);
401 /* If ibfd was a stubbed coff image, copy the stub from that bfd
406 go32_stubbed_coff_bfd_copy_private_bfd_data (ibfd, obfd)
410 /* check if both are the same targets */
411 if (ibfd->xvec != obfd->xvec)
414 /* check if both have a valid stub */
415 if (bfd_coff_go32stub (ibfd) == NULL
416 || bfd_coff_go32stub (obfd) == NULL)
419 /* Now copy the stub */
420 memcpy (bfd_coff_go32stub (obfd), bfd_coff_go32stub (ibfd), STUBSIZE);