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