1/* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
2   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2007, 2009
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/* This macro is used, because I cannot assume the endianess of the
106   host system.  */
107#define _H(index) (H_GET_16 (abfd, (header+index*2)))
108
109/* These bytes are a 2048-byte DOS executable, which loads the COFF
110   image into memory and then runs it. It is called 'stub'.  */
111
112static const unsigned char stub_bytes[GO32_STUBSIZE] =
113{
114#include "go32stub.h"
115};
116
117/*
118   I have not commented each swap function below, because the
119   technique is in any function the same. For the ...in function,
120   all the pointers are adjusted by adding GO32_STUBSIZE and for the
121   ...out function, it is subtracted first and after calling the
122   standard swap function it is reset to the old value.  */
123
124/* This macro is used for adjusting the filepointers, which
125   is done only, if the pointer is nonzero.  */
126
127#define ADJUST_VAL(val,diff) \
128  if (val != 0) val += diff
129
130static void
131adjust_filehdr_in_post  (abfd, src, dst)
132     bfd *abfd ATTRIBUTE_UNUSED;
133     PTR src;
134     PTR dst;
135{
136  FILHDR *filehdr_src = (FILHDR *) src;
137  struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
138
139  ADJUST_VAL (filehdr_dst->f_symptr, GO32_STUBSIZE);
140
141  /* Save now the stub to be used later.  Put the stub data to FILEHDR_DST
142     first as coff_data (abfd) still does not exist.  It may not even be ever
143     created as we are just checking the file format of ABFD.  */
144  memcpy (filehdr_dst->go32stub, filehdr_src->stub, GO32_STUBSIZE);
145  filehdr_dst->f_flags |= F_GO32STUB;
146}
147
148static void
149adjust_filehdr_out_pre  (abfd, in, out)
150     bfd *abfd;
151     PTR in;
152     PTR out;
153{
154  struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
155  FILHDR *filehdr_out = (FILHDR *) out;
156
157  /* Generate the stub.  */
158  create_go32_stub (abfd);
159
160  /* Copy the stub to the file header.  */
161  if (coff_data (abfd)->go32stub != NULL)
162    memcpy (filehdr_out->stub, coff_data (abfd)->go32stub, GO32_STUBSIZE);
163  else
164    /* Use the default.  */
165    memcpy (filehdr_out->stub, stub_bytes, GO32_STUBSIZE);
166
167  ADJUST_VAL (filehdr_in->f_symptr, -GO32_STUBSIZE);
168}
169
170static void
171adjust_filehdr_out_post  (abfd, in, out)
172     bfd *abfd ATTRIBUTE_UNUSED;
173     PTR in;
174     PTR out ATTRIBUTE_UNUSED;
175{
176  struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
177  /* Undo the above change.  */
178  ADJUST_VAL (filehdr_in->f_symptr, GO32_STUBSIZE);
179}
180
181static void
182adjust_scnhdr_in_post  (abfd, ext, in)
183     bfd *abfd ATTRIBUTE_UNUSED;
184     PTR ext ATTRIBUTE_UNUSED;
185     PTR in;
186{
187  struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
188
189  ADJUST_VAL (scnhdr_int->s_scnptr, GO32_STUBSIZE);
190  ADJUST_VAL (scnhdr_int->s_relptr, GO32_STUBSIZE);
191  ADJUST_VAL (scnhdr_int->s_lnnoptr, GO32_STUBSIZE);
192}
193
194static void
195adjust_scnhdr_out_pre  (abfd, in, out)
196     bfd *abfd ATTRIBUTE_UNUSED;
197     PTR in;
198     PTR out ATTRIBUTE_UNUSED;
199{
200  struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
201
202  ADJUST_VAL (scnhdr_int->s_scnptr, -GO32_STUBSIZE);
203  ADJUST_VAL (scnhdr_int->s_relptr, -GO32_STUBSIZE);
204  ADJUST_VAL (scnhdr_int->s_lnnoptr, -GO32_STUBSIZE);
205}
206
207static void
208adjust_scnhdr_out_post (abfd, in, out)
209     bfd *abfd ATTRIBUTE_UNUSED;
210     PTR in;
211     PTR out ATTRIBUTE_UNUSED;
212{
213  struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
214
215  ADJUST_VAL (scnhdr_int->s_scnptr, GO32_STUBSIZE);
216  ADJUST_VAL (scnhdr_int->s_relptr, GO32_STUBSIZE);
217  ADJUST_VAL (scnhdr_int->s_lnnoptr, GO32_STUBSIZE);
218}
219
220static void
221adjust_aux_in_post  (abfd, ext1, type, in_class, indx, numaux, in1)
222     bfd *abfd ATTRIBUTE_UNUSED;
223     PTR ext1 ATTRIBUTE_UNUSED;
224     int type;
225     int in_class;
226     int indx ATTRIBUTE_UNUSED;
227     int numaux ATTRIBUTE_UNUSED;
228     PTR in1;
229{
230  union internal_auxent *in = (union internal_auxent *) in1;
231
232  if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
233      || ISTAG (in_class))
234    {
235      ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, GO32_STUBSIZE);
236    }
237}
238
239static void
240adjust_aux_out_pre  (abfd, inp, type, in_class, indx, numaux, extp)
241     bfd *abfd ATTRIBUTE_UNUSED;
242     PTR inp;
243     int type;
244     int in_class;
245     int indx ATTRIBUTE_UNUSED;
246     int numaux ATTRIBUTE_UNUSED;
247     PTR extp ATTRIBUTE_UNUSED;
248{
249  union internal_auxent *in = (union internal_auxent *) inp;
250
251  if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
252      || ISTAG (in_class))
253    {
254      ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, -GO32_STUBSIZE);
255    }
256}
257
258static void
259adjust_aux_out_post (abfd, inp, type, in_class, indx, numaux, extp)
260     bfd *abfd ATTRIBUTE_UNUSED;
261     PTR inp;
262     int type;
263     int in_class;
264     int indx ATTRIBUTE_UNUSED;
265     int numaux ATTRIBUTE_UNUSED;
266     PTR extp ATTRIBUTE_UNUSED;
267{
268  union internal_auxent *in = (union internal_auxent *) inp;
269
270  if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type)
271      || ISTAG (in_class))
272    {
273      ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, GO32_STUBSIZE);
274    }
275}
276
277/* That's the function, which creates the stub. There are
278   different cases from where the stub is taken.
279   At first the environment variable $(GO32STUB) is checked and then
280   $(STUB) if it was not set.
281   If it exists and points to a valid stub the stub is taken from
282   that file. This file can be also a whole executable file, because
283   the stub is computed from the exe information at the start of that
284   file.
285
286   If there was any error, the standard stub (compiled in this file)
287   is taken.  */
288
289static void
290create_go32_stub (abfd)
291     bfd *abfd;
292{
293  /* Do it only once.  */
294  if (coff_data (abfd)->go32stub == NULL)
295    {
296      char *stub;
297      struct stat st;
298      int f;
299      unsigned char header[10];
300      char magic[8];
301      unsigned long coff_start;
302      long exe_start;
303
304      /* Check at first the environment variable $(GO32STUB).  */
305      stub = getenv ("GO32STUB");
306      /* Now check the environment variable $(STUB).  */
307      if (stub == NULL)
308	stub = getenv ("STUB");
309      if (stub == NULL)
310	goto stub_end;
311      if (stat (stub, &st) != 0)
312	goto stub_end;
313#ifdef O_BINARY
314      f = open (stub, O_RDONLY | O_BINARY);
315#else
316      f = open (stub, O_RDONLY);
317#endif
318      if (f < 0)
319	goto stub_end;
320      if (read (f, &header, sizeof (header)) < 0)
321	{
322	  close (f);
323	  goto stub_end;
324	}
325      if (_H (0) != 0x5a4d)	/* It is not an exe file.  */
326	{
327	  close (f);
328	  goto stub_end;
329	}
330      /* Compute the size of the stub (it is every thing up
331         to the beginning of the coff image).  */
332      coff_start = (long) _H (2) * 512L;
333      if (_H (1))
334	coff_start += (long) _H (1) - 512L;
335
336      /* Currently there is only a fixed stub size of 2048 bytes
337         supported.  */
338      if (coff_start != 2048)
339	{
340	  close (f);
341	  goto stub_end;
342	}
343      exe_start = _H (4) * 16;
344      if ((long) lseek (f, exe_start, SEEK_SET) != exe_start)
345	{
346	  close (f);
347	  goto stub_end;
348	}
349      if (read (f, &magic, 8) != 8)
350	{
351	  close (f);
352	  goto stub_end;
353	}
354      if (! CONST_STRNEQ (magic, "go32stub"))
355	{
356	  close (f);
357	  goto stub_end;
358	}
359      /* Now we found a correct stub (hopefully).  */
360      coff_data (abfd)->go32stub = bfd_alloc (abfd, (bfd_size_type) coff_start);
361      if (coff_data (abfd)->go32stub == NULL)
362	{
363	  close (f);
364	  return;
365	}
366      lseek (f, 0L, SEEK_SET);
367      if ((unsigned long) read (f, coff_data (abfd)->go32stub, coff_start)
368	  != coff_start)
369	{
370	  bfd_release (abfd, coff_data (abfd)->go32stub);
371	  coff_data (abfd)->go32stub = NULL;
372	}
373      close (f);
374    }
375stub_end:
376  /* There was something wrong above, so use now the standard builtin
377     stub.  */
378  if (coff_data (abfd)->go32stub == NULL)
379    {
380      coff_data (abfd)->go32stub
381	= bfd_alloc (abfd, (bfd_size_type) GO32_STUBSIZE);
382      if (coff_data (abfd)->go32stub == NULL)
383	return;
384      memcpy (coff_data (abfd)->go32stub, stub_bytes, GO32_STUBSIZE);
385    }
386}
387
388/* If ibfd was a stubbed coff image, copy the stub from that bfd
389   to the new obfd.  */
390
391static bfd_boolean
392go32_stubbed_coff_bfd_copy_private_bfd_data  (ibfd, obfd)
393     bfd *ibfd;
394     bfd *obfd;
395{
396  /* Check if both are the same targets.  */
397  if (ibfd->xvec != obfd->xvec)
398    return TRUE;
399
400  /* Check if we have a source stub.  */
401  if (coff_data (ibfd)->go32stub == NULL)
402    return TRUE;
403
404  /* As adjust_filehdr_out_pre may get called only after this function,
405     optionally allocate the output stub.  */
406  if (coff_data (obfd)->go32stub == NULL)
407    coff_data (obfd)->go32stub = bfd_alloc (obfd,
408					  (bfd_size_type) GO32_STUBSIZE);
409
410  /* Now copy the stub.  */
411  if (coff_data (obfd)->go32stub != NULL)
412    memcpy (coff_data (obfd)->go32stub, coff_data (ibfd)->go32stub,
413	    GO32_STUBSIZE);
414
415  return TRUE;
416}
417