1/* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
2   Copyright (C) 1997-2020 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22/* This file handles now also stubbed coff images. The stub is a small
23   DOS executable program before the coff image to load it in memory
24   and execute it. This is needed, because DOS cannot run coff files.
25
26   The COFF image is loaded in memory without the stub attached, so
27   all offsets are relative to the beginning of the image, not the
28   actual file.  We handle this in bfd by setting bfd->origin to where
29   the COFF image starts.  */
30
31#define TARGET_SYM		i386_coff_go32stubbed_vec
32#define TARGET_NAME		"coff-go32-exe"
33#define TARGET_UNDERSCORE	'_'
34#define COFF_GO32_EXE
35#define COFF_LONG_SECTION_NAMES
36#define COFF_SUPPORT_GNU_LINKONCE
37#define COFF_LONG_FILENAMES
38
39#define COFF_SECTION_ALIGNMENT_ENTRIES \
40{ COFF_SECTION_NAME_EXACT_MATCH (".data"), \
41  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
42{ COFF_SECTION_NAME_EXACT_MATCH (".text"), \
43  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
44{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
45  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
46{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \
47  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
48
49/* Section contains extended relocations. */
50#define IMAGE_SCN_LNK_NRELOC_OVFL (0x01000000)
51
52#include "sysdep.h"
53#include "bfd.h"
54#include "coff/msdos.h"
55
56static bfd_cleanup go32exe_check_format (bfd *);
57static bfd_boolean go32exe_write_object_contents (bfd *);
58static bfd_boolean go32exe_mkobject (bfd *);
59static bfd_boolean go32exe_copy_private_bfd_data (bfd *, bfd *);
60
61/* Defined in coff-go32.c.  */
62bfd_boolean _bfd_go32_mkobject (bfd *);
63void _bfd_go32_swap_scnhdr_in (bfd *, void *, void *);
64unsigned int _bfd_go32_swap_scnhdr_out (bfd *, void *, void *);
65
66#define COFF_CHECK_FORMAT go32exe_check_format
67#define COFF_WRITE_CONTENTS go32exe_write_object_contents
68#define coff_mkobject go32exe_mkobject
69#define coff_bfd_copy_private_bfd_data go32exe_copy_private_bfd_data
70#define coff_SWAP_scnhdr_in _bfd_go32_swap_scnhdr_in
71#define coff_SWAP_scnhdr_out _bfd_go32_swap_scnhdr_out
72
73#include "coff-i386.c"
74
75/* This macro is used, because I cannot assume the endianness of the
76   host system.  */
77#define _H(index) (H_GET_16 (abfd, (header + index * 2)))
78
79/* These bytes are a 2048-byte DOS executable, which loads the COFF
80   image into memory and then runs it. It is called 'stub'.  */
81#define GO32EXE_DEFAULT_STUB_SIZE 2048
82static const unsigned char go32exe_default_stub[GO32EXE_DEFAULT_STUB_SIZE] =
83{
84#include "go32stub.h"
85};
86
87/* Temporary location for stub read from input file.  */
88static char * go32exe_temp_stub = NULL;
89static bfd_size_type go32exe_temp_stub_size = 0;
90
91/* That's the function, which creates the stub. There are
92   different cases from where the stub is taken.
93   At first the environment variable $(GO32STUB) is checked and then
94   $(STUB) if it was not set.
95   If it exists and points to a valid stub the stub is taken from
96   that file. This file can be also a whole executable file, because
97   the stub is computed from the exe information at the start of that
98   file.
99
100   If there was any error, the standard stub (compiled in this file)
101   is taken.
102
103   Ideally this function should exec '$(TARGET)-stubify' to generate
104   a stub, like gcc does.  */
105
106static void
107go32exe_create_stub (bfd *abfd)
108{
109  /* Do it only once.  */
110  if (coff_data (abfd)->stub == NULL)
111    {
112      char *stub;
113      struct stat st;
114      int f;
115      unsigned char header[10];
116      char magic[8];
117      unsigned long coff_start;
118      long exe_start;
119
120      /* If we read a stub from an input file, use that one.  */
121      if (go32exe_temp_stub != NULL)
122	{
123	  coff_data (abfd)->stub = bfd_alloc (abfd,
124						  go32exe_temp_stub_size);
125	  if (coff_data (abfd)->stub == NULL)
126	    return;
127	  memcpy (coff_data (abfd)->stub, go32exe_temp_stub,
128		  go32exe_temp_stub_size);
129	  coff_data (abfd)->stub_size = go32exe_temp_stub_size;
130	  free (go32exe_temp_stub);
131	  go32exe_temp_stub = NULL;
132	  go32exe_temp_stub_size = 0;
133	  return;
134	}
135
136      /* Check at first the environment variable $(GO32STUB).  */
137      stub = getenv ("GO32STUB");
138      /* Now check the environment variable $(STUB).  */
139      if (stub == NULL)
140	stub = getenv ("STUB");
141      if (stub == NULL)
142	goto stub_end;
143      if (stat (stub, &st) != 0)
144	goto stub_end;
145#ifdef O_BINARY
146      f = open (stub, O_RDONLY | O_BINARY);
147#else
148      f = open (stub, O_RDONLY);
149#endif
150      if (f < 0)
151	goto stub_end;
152      if (read (f, &header, sizeof (header)) < 0)
153	{
154	  close (f);
155	  goto stub_end;
156	}
157      if (_H (0) != 0x5a4d)	/* It is not an exe file.  */
158	{
159	  close (f);
160	  goto stub_end;
161	}
162      /* Compute the size of the stub (it is every thing up
163	 to the beginning of the coff image).  */
164      coff_start = (long) _H (2) * 512L;
165      if (_H (1))
166	coff_start += (long) _H (1) - 512L;
167
168      exe_start = _H (4) * 16;
169      if ((long) lseek (f, exe_start, SEEK_SET) != exe_start)
170	{
171	  close (f);
172	  goto stub_end;
173	}
174      if (read (f, &magic, 8) != 8)
175	{
176	  close (f);
177	  goto stub_end;
178	}
179      if (! CONST_STRNEQ (magic, "go32stub"))
180	{
181	  close (f);
182	  goto stub_end;
183	}
184      /* Now we found a correct stub (hopefully).  */
185      coff_data (abfd)->stub = bfd_alloc (abfd, (bfd_size_type) coff_start);
186      if (coff_data (abfd)->stub == NULL)
187	{
188	  close (f);
189	  return;
190	}
191      lseek (f, 0L, SEEK_SET);
192      if ((unsigned long) read (f, coff_data (abfd)->stub, coff_start)
193	  != coff_start)
194	{
195	  bfd_release (abfd, coff_data (abfd)->stub);
196	  coff_data (abfd)->stub = NULL;
197	}
198      else
199	coff_data (abfd)->stub_size = coff_start;
200      close (f);
201    }
202 stub_end:
203  /* There was something wrong above, so use now the standard builtin
204     stub.  */
205  if (coff_data (abfd)->stub == NULL)
206    {
207      coff_data (abfd)->stub
208	= bfd_alloc (abfd, (bfd_size_type) GO32EXE_DEFAULT_STUB_SIZE);
209      if (coff_data (abfd)->stub == NULL)
210	return;
211      memcpy (coff_data (abfd)->stub, go32exe_default_stub,
212	      GO32EXE_DEFAULT_STUB_SIZE);
213      coff_data (abfd)->stub_size = GO32EXE_DEFAULT_STUB_SIZE;
214    }
215}
216
217/* If ibfd was a stubbed coff image, copy the stub from that bfd
218   to the new obfd.  */
219
220static bfd_boolean
221go32exe_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
222{
223  /* Check if both are the same targets.  */
224  if (ibfd->xvec != obfd->xvec)
225    return TRUE;
226
227  /* Make sure we have a source stub.  */
228  BFD_ASSERT (coff_data (ibfd)->stub != NULL);
229
230  /* Reallocate the output stub if necessary.  */
231  if (coff_data (ibfd)->stub_size > coff_data (obfd)->stub_size)
232    coff_data (obfd)->stub = bfd_alloc (obfd, coff_data (ibfd)->stub_size);
233  if (coff_data (obfd)->stub == NULL)
234    return FALSE;
235
236  /* Now copy the stub.  */
237  memcpy (coff_data (obfd)->stub, coff_data (ibfd)->stub,
238	  coff_data (ibfd)->stub_size);
239  coff_data (obfd)->stub_size = coff_data (ibfd)->stub_size;
240  obfd->origin = coff_data (obfd)->stub_size;
241
242  return TRUE;
243}
244
245/* Cleanup function, returned from check_format hook.  */
246
247static void
248go32exe_cleanup (bfd *abfd)
249{
250  abfd->origin = 0;
251
252  free (go32exe_temp_stub);
253  go32exe_temp_stub = NULL;
254  go32exe_temp_stub_size = 0;
255}
256
257/* Check that there is a GO32 stub and read it to go32exe_temp_stub.
258   Then set abfd->origin so that the COFF image is read at the correct
259   file offset.  */
260
261static bfd_cleanup
262go32exe_check_format (bfd *abfd)
263{
264  struct external_DOS_hdr filehdr_dos;
265  uint16_t num_pages;
266  uint16_t last_page_size;
267  uint32_t header_end;
268  bfd_size_type stubsize;
269
270  /* This format can not appear in an archive.  */
271  if (abfd->origin != 0)
272    {
273      bfd_set_error (bfd_error_wrong_format);
274      return NULL;
275    }
276
277  bfd_set_error (bfd_error_system_call);
278
279  /* Read in the stub file header, which is a DOS MZ executable.  */
280  if (bfd_bread (&filehdr_dos, DOS_HDR_SIZE, abfd) != DOS_HDR_SIZE)
281    goto fail;
282
283  /* Make sure that this is an MZ executable.  */
284  if (H_GET_16 (abfd, filehdr_dos.e_magic) != IMAGE_DOS_SIGNATURE)
285    goto fail_format;
286
287  /* Determine the size of the stub  */
288  num_pages = H_GET_16 (abfd, filehdr_dos.e_cp);
289  last_page_size = H_GET_16 (abfd, filehdr_dos.e_cblp);
290  stubsize = num_pages * 512;
291  if (last_page_size != 0)
292    stubsize += last_page_size - 512;
293
294  /* Save now the stub to be used later.  Put the stub data to a temporary
295     location first as tdata still does not exist.  It may not even
296     be ever created if we are just checking the file format of ABFD.  */
297  bfd_seek (abfd, 0, SEEK_SET);
298  go32exe_temp_stub = bfd_malloc (stubsize);
299  if (go32exe_temp_stub == NULL)
300    goto fail;
301  if (bfd_bread (go32exe_temp_stub, stubsize, abfd) != stubsize)
302    goto fail;
303  go32exe_temp_stub_size = stubsize;
304
305  /* Confirm that this is a go32stub.  */
306  header_end = H_GET_16 (abfd, filehdr_dos.e_cparhdr) * 16UL;
307  if (! CONST_STRNEQ (go32exe_temp_stub + header_end, "go32stub"))
308    goto fail_format;
309
310  /* Set origin to where the COFF header starts and seek there.  */
311  abfd->origin = stubsize;
312  if (bfd_seek (abfd, 0, SEEK_SET) != 0)
313    goto fail;
314
315  /* Call coff_object_p to read the COFF image.  If this fails then the file
316     must be just a stub with no COFF data attached.  */
317  bfd_cleanup cleanup = coff_object_p (abfd);
318  if (cleanup == NULL)
319    goto fail;
320  BFD_ASSERT (cleanup == _bfd_no_cleanup);
321
322  return go32exe_cleanup;
323
324 fail_format:
325  bfd_set_error (bfd_error_wrong_format);
326 fail:
327  go32exe_cleanup (abfd);
328  return NULL;
329}
330
331/* Write the stub to the output file, then call coff_write_object_contents.  */
332
333static bfd_boolean
334go32exe_write_object_contents (bfd *abfd)
335{
336  const bfd_size_type pos = bfd_tell (abfd);
337  const bfd_size_type stubsize = coff_data (abfd)->stub_size;
338
339  BFD_ASSERT (stubsize != 0);
340
341  bfd_set_error (bfd_error_system_call);
342
343  /* Write the stub.  */
344  abfd->origin = 0;
345  if (bfd_seek (abfd, 0, SEEK_SET) != 0)
346    return FALSE;
347  if (bfd_bwrite (coff_data (abfd)->stub, stubsize, abfd) != stubsize)
348    return FALSE;
349
350  /* Seek back to where we were.  */
351  abfd->origin = stubsize;
352  if (bfd_seek (abfd, pos, SEEK_SET) != 0)
353    return FALSE;
354
355  return coff_write_object_contents (abfd);
356}
357
358/* mkobject hook.  Called directly through bfd_set_format or via
359   coff_mkobject_hook etc from bfd_check_format.  */
360
361static bfd_boolean
362go32exe_mkobject (bfd *abfd)
363{
364  /* Don't output to an archive.  */
365  if (abfd->my_archive != NULL)
366    return FALSE;
367
368  if (!_bfd_go32_mkobject (abfd))
369    return FALSE;
370
371  go32exe_create_stub (abfd);
372  if (coff_data (abfd)->stub == NULL)
373    {
374      bfd_release (abfd, coff_data (abfd));
375      return FALSE;
376    }
377  abfd->origin = coff_data (abfd)->stub_size;
378
379  return TRUE;
380}
381