xref: /openbsd/gnu/usr.bin/binutils/bfd/coff-stgo32.c (revision db3296cf)
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.
4 
5    This file is part of BFD, the Binary File Descriptor library.
6 
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.
11 
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.
16 
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.  */
20 
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.
24 
25    All the functions below are called by the corresponding functions
26    from coffswap.h.
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.
33 
34    To be compatible with any existing executables I have fixed this
35    here and NOT in the DJGPP startup code.
36  */
37 
38 #define TARGET_SYM		go32stubbedcoff_vec
39 #define TARGET_NAME		"coff-go32-exe"
40 #define TARGET_UNDERSCORE	'_'
41 #define COFF_GO32_EXE
42 #define COFF_LONG_SECTION_NAMES
43 #define COFF_SUPPORT_GNU_LINKONCE
44 #define COFF_LONG_FILENAMES
45 
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 
52 #include "bfd.h"
53 
54 /* At first the prototypes */
55 
56 static void
57 adjust_filehdr_in_post PARAMS ((bfd * abfd, PTR src, PTR dst));
58 static void
59 adjust_filehdr_out_pre PARAMS ((bfd * abfd, PTR in, PTR out));
60 static void
61 adjust_filehdr_out_post PARAMS ((bfd * abfd, PTR in, PTR out));
62 
63 static void
64 adjust_scnhdr_in_post PARAMS ((bfd * abfd, PTR ext, PTR in));
65 static void
66 adjust_scnhdr_out_pre PARAMS ((bfd * abfd, PTR in, PTR out));
67 static void
68 adjust_scnhdr_out_post PARAMS ((bfd * abfd, PTR in, PTR out));
69 
70 static void
71 adjust_aux_in_post PARAMS ((bfd * abfd, PTR ext1, int type, int class, int indx,
72 			    int numaux, PTR in1));
73 static void
74 adjust_aux_out_pre PARAMS ((bfd * abfd, PTR inp, int type, int class, int indx,
75 			    int numaux, PTR extp));
76 static void
77 adjust_aux_out_post PARAMS ((bfd * abfd, PTR inp, int type, int class, int indx,
78 			     int numaux, PTR extp));
79 
80 static void
81 create_go32_stub PARAMS ((bfd * abfd));
82 
83 /*
84    All that ..._PRE and ...POST functions are called from the corresponding
85    coff_swap... functions. The ...PRE functions are called at the beginning
86    of the function and the ...POST functions at the end of the swap routines.
87  */
88 
89 #define COFF_ADJUST_FILEHDR_IN_POST adjust_filehdr_in_post
90 #define COFF_ADJUST_FILEHDR_OUT_PRE adjust_filehdr_out_pre
91 #define COFF_ADJUST_FILEHDR_OUT_POST adjust_filehdr_out_post
92 
93 #define COFF_ADJUST_SCNHDR_IN_POST adjust_scnhdr_in_post
94 #define COFF_ADJUST_SCNHDR_OUT_PRE adjust_scnhdr_out_pre
95 #define COFF_ADJUST_SCNHDR_OUT_POST adjust_scnhdr_out_post
96 
97 #define COFF_ADJUST_AUX_IN_POST adjust_aux_in_post
98 #define COFF_ADJUST_AUX_OUT_PRE adjust_aux_out_pre
99 #define COFF_ADJUST_AUX_OUT_POST adjust_aux_out_post
100 
101 static boolean
102   go32_stubbed_coff_bfd_copy_private_bfd_data PARAMS ((bfd * ibfd, bfd * obfd));
103 
104 #define coff_bfd_copy_private_bfd_data go32_stubbed_coff_bfd_copy_private_bfd_data
105 
106 #include "coff-i386.c"
107 
108 /* I hold in the usrdata the stub */
109 #define bfd_coff_go32stub bfd_usrdata
110 
111 /* This macro is used, because I cannot assume the endianess of the
112    host system */
113 #define _H(index) (bfd_h_get_16(abfd, (bfd_byte *) (header+index*2)))
114 
115 /* These bytes are a 2048-byte DOS executable, which loads the COFF
116    image into memory and then runs it. It is called 'stub' */
117 
118 static unsigned char stub_bytes[STUBSIZE] =
119 {
120 #include "go32stub.h"
121 };
122 
123 /*
124    I have not commented each swap function below, because the
125    technique is in any function the same. For the ...in function,
126    all the pointers are adjusted by adding STUBSIZE and for the
127    ...out function, it is subtracted first and after calling the
128    standard swap function it is reset to the old value */
129 
130 /* This macro is used for adjusting the filepointers, which
131    is done only, if the pointer is nonzero */
132 
133 #define ADJUST_VAL(val,diff) \
134   if (val != 0) val += diff
135 
136 static void
137 adjust_filehdr_in_post  (abfd, src, dst)
138      bfd *abfd;
139      PTR src;
140      PTR dst;
141 {
142   FILHDR *filehdr_src = (FILHDR *) src;
143   struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
144 
145   ADJUST_VAL (filehdr_dst->f_symptr, STUBSIZE);
146 
147   /* Save now the stub to be used later */
148   bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, STUBSIZE);
149 
150   /* Since this function returns no status, I do not set here
151      any bfd_error_...
152      That means, before the use of bfd_coff_go32stub (), this value
153      should be checked if it is != NULL */
154   if (bfd_coff_go32stub (abfd) == NULL)
155     return;
156   memcpy (bfd_coff_go32stub (abfd), filehdr_src->stub, STUBSIZE);
157 }
158 
159 static void
160 adjust_filehdr_out_pre  (abfd, in, out)
161      bfd *abfd;
162      PTR in;
163      PTR out;
164 {
165   struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
166   FILHDR *filehdr_out = (FILHDR *) out;
167 
168   /* Generate the stub */
169   create_go32_stub (abfd);
170 
171   /* Copy the stub to the file header */
172   if (bfd_coff_go32stub (abfd) != NULL)
173     memcpy (filehdr_out->stub, bfd_coff_go32stub (abfd), STUBSIZE);
174   else
175     /* use the default */
176     memcpy (filehdr_out->stub, stub_bytes, STUBSIZE);
177 
178   ADJUST_VAL (filehdr_in->f_symptr, -STUBSIZE);
179 }
180 
181 static void
182 adjust_filehdr_out_post  (abfd, in, out)
183      bfd *abfd ATTRIBUTE_UNUSED;
184      PTR in;
185      PTR out ATTRIBUTE_UNUSED;
186 {
187   struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
188   /* undo the above change */
189   ADJUST_VAL (filehdr_in->f_symptr, STUBSIZE);
190 }
191 
192 static void
193 adjust_scnhdr_in_post  (abfd, ext, in)
194      bfd *abfd ATTRIBUTE_UNUSED;
195      PTR ext ATTRIBUTE_UNUSED;
196      PTR in;
197 {
198   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
199 
200   ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE);
201   ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE);
202   ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE);
203 }
204 
205 static void
206 adjust_scnhdr_out_pre  (abfd, in, out)
207      bfd *abfd ATTRIBUTE_UNUSED;
208      PTR in;
209      PTR out ATTRIBUTE_UNUSED;
210 {
211   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
212 
213   ADJUST_VAL (scnhdr_int->s_scnptr, -STUBSIZE);
214   ADJUST_VAL (scnhdr_int->s_relptr, -STUBSIZE);
215   ADJUST_VAL (scnhdr_int->s_lnnoptr, -STUBSIZE);
216 }
217 
218 static void
219 adjust_scnhdr_out_post (abfd, in, out)
220      bfd *abfd ATTRIBUTE_UNUSED;
221      PTR in;
222      PTR out ATTRIBUTE_UNUSED;
223 {
224   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
225 
226   ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE);
227   ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE);
228   ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE);
229 }
230 
231 static void
232 adjust_aux_in_post  (abfd, ext1, type, class, indx, numaux, in1)
233      bfd *abfd ATTRIBUTE_UNUSED;
234      PTR ext1 ATTRIBUTE_UNUSED;
235      int type;
236      int class;
237      int indx ATTRIBUTE_UNUSED;
238      int numaux ATTRIBUTE_UNUSED;
239      PTR in1;
240 {
241   union internal_auxent *in = (union internal_auxent *) in1;
242 
243   if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
244     {
245       ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE);
246     }
247 }
248 
249 static void
250 adjust_aux_out_pre  (abfd, inp, type, class, indx, numaux, extp)
251      bfd *abfd ATTRIBUTE_UNUSED;
252      PTR inp;
253      int type;
254      int class;
255      int indx ATTRIBUTE_UNUSED;
256      int numaux ATTRIBUTE_UNUSED;
257      PTR extp ATTRIBUTE_UNUSED;
258 {
259   union internal_auxent *in = (union internal_auxent *) inp;
260 
261   if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
262     {
263       ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, -STUBSIZE);
264     }
265 }
266 
267 static void
268 adjust_aux_out_post (abfd, inp, type, class, indx, numaux, extp)
269      bfd *abfd ATTRIBUTE_UNUSED;
270      PTR inp;
271      int type;
272      int class;
273      int indx ATTRIBUTE_UNUSED;
274      int numaux ATTRIBUTE_UNUSED;
275      PTR extp ATTRIBUTE_UNUSED;
276 {
277   union internal_auxent *in = (union internal_auxent *) inp;
278 
279   if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
280     {
281       ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE);
282     }
283 }
284 
285 /*
286    That's the function, which creates the stub. There are
287    different cases from where the stub is taken.
288    At first the environment variable $(GO32STUB) is checked and then
289    $(STUB) if it was not set.
290    If it exists and points to a valid stub the stub is taken from
291    that file. This file can be also a whole executable file, because
292    the stub is computed from the exe information at the start of that
293    file.
294 
295    If there was any error, the standard stub (compiled in this file)
296    is taken.
297  */
298 
299 static void
300 create_go32_stub (abfd)
301      bfd *abfd;
302 {
303   /* Do it only once */
304   if (bfd_coff_go32stub (abfd) == NULL)
305     {
306       char *stub;
307       struct stat st;
308       int f;
309       unsigned char header[10];
310       char magic[8];
311       unsigned long coff_start, exe_start;
312 
313       /* Check at first the environment variable $(GO32STUB) */
314       stub = getenv ("GO32STUB");
315       /* Now check the environment variable $(STUB) */
316       if (stub == NULL)
317 	stub = getenv ("STUB");
318       if (stub == NULL)
319 	goto stub_end;
320       if (stat (stub, &st) != 0)
321 	goto stub_end;
322 #ifdef O_BINARY
323       f = open (stub, O_RDONLY | O_BINARY);
324 #else
325       f = open (stub, O_RDONLY);
326 #endif
327       if (f < 0)
328 	goto stub_end;
329       if (read (f, &header, sizeof (header)) < 0)
330 	{
331 	  close (f);
332 	  goto stub_end;
333 	}
334       if (_H (0) != 0x5a4d)	/* it is not an exe file */
335 	{
336 	  close (f);
337 	  goto stub_end;
338 	}
339       /* Compute the size of the stub (it is every thing up
340          to the beginning of the coff image) */
341       coff_start = (long) _H (2) * 512L;
342       if (_H (1))
343 	coff_start += (long) _H (1) - 512L;
344 
345       /* Currently there is only a fixed stub size of 2048 bytes
346          supported */
347       if (coff_start != 2048)
348 	{
349 	  close (f);
350 	  goto stub_end;
351 	}
352       exe_start = _H (4) * 16;
353       if ((unsigned long) lseek (f, exe_start, SEEK_SET) != exe_start)
354 	{
355 	  close (f);
356 	  goto stub_end;
357 	}
358       if (read (f, &magic, 8) != 8)
359 	{
360 	  close (f);
361 	  goto stub_end;
362 	}
363       if (memcmp (magic, "go32stub", 8) != 0)
364 	{
365 	  close (f);
366 	  goto stub_end;
367 	}
368       /* Now we found a correct stub (hopefully) */
369       bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, coff_start);
370       if (bfd_coff_go32stub (abfd) == NULL)
371 	{
372 	  close (f);
373 	  return;
374 	}
375       lseek (f, 0L, SEEK_SET);
376       if ((unsigned long) read (f, bfd_coff_go32stub (abfd), coff_start)
377 	  != coff_start)
378 	{
379 	  bfd_release (abfd, bfd_coff_go32stub (abfd));
380 	  bfd_coff_go32stub (abfd) = NULL;
381 	}
382       close (f);
383     }
384 stub_end:
385   /* There was something wrong above, so use now the standard builtin
386      stub */
387   if (bfd_coff_go32stub (abfd) == NULL)
388     {
389       bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, STUBSIZE);
390       if (bfd_coff_go32stub (abfd) == NULL)
391 	{
392 	  return;
393 	}
394 
395       memcpy (bfd_coff_go32stub (abfd), stub_bytes, STUBSIZE);
396     }
397 }
398 
399 /* If ibfd was a stubbed coff image, copy the stub from that bfd
400    to the new obfd.
401  */
402 
403 static boolean
404 go32_stubbed_coff_bfd_copy_private_bfd_data  (ibfd, obfd)
405      bfd *ibfd;
406      bfd *obfd;
407 {
408   /* check if both are the same targets */
409   if (ibfd->xvec != obfd->xvec)
410     return true;
411 
412   /* check if both have a valid stub */
413   if (bfd_coff_go32stub (ibfd) == NULL
414       || bfd_coff_go32stub (obfd) == NULL)
415     return true;
416 
417   /* Now copy the stub */
418   memcpy (bfd_coff_go32stub (obfd), bfd_coff_go32stub (ibfd), STUBSIZE);
419 
420   return true;
421 }
422