1 /* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
2    Copyright (C) 1997-2021 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 
56 static bfd_cleanup go32exe_check_format (bfd *);
57 static bool go32exe_write_object_contents (bfd *);
58 static bool go32exe_mkobject (bfd *);
59 static bool go32exe_copy_private_bfd_data (bfd *, bfd *);
60 
61 /* Defined in coff-go32.c.  */
62 bool _bfd_go32_mkobject (bfd *);
63 void _bfd_go32_swap_scnhdr_in (bfd *, void *, void *);
64 unsigned 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
82 static 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.  */
88 static char * go32exe_temp_stub = NULL;
89 static 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 
106 static void
go32exe_create_stub(bfd * abfd)107 go32exe_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 (! startswith (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 
220 static bool
go32exe_copy_private_bfd_data(bfd * ibfd,bfd * obfd)221 go32exe_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 
247 static void
go32exe_cleanup(bfd * abfd)248 go32exe_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 
261 static bfd_cleanup
go32exe_check_format(bfd * abfd)262 go32exe_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 (go32exe_temp_stub_size < header_end
308       || go32exe_temp_stub_size - header_end < sizeof "go32stub" - 1
309       || !startswith (go32exe_temp_stub + header_end, "go32stub"))
310     goto fail_format;
311 
312   /* Set origin to where the COFF header starts and seek there.  */
313   abfd->origin = stubsize;
314   if (bfd_seek (abfd, 0, SEEK_SET) != 0)
315     goto fail;
316 
317   /* Call coff_object_p to read the COFF image.  If this fails then the file
318      must be just a stub with no COFF data attached.  */
319   bfd_cleanup cleanup = coff_object_p (abfd);
320   if (cleanup == NULL)
321     goto fail;
322   BFD_ASSERT (cleanup == _bfd_no_cleanup);
323 
324   return go32exe_cleanup;
325 
326  fail_format:
327   bfd_set_error (bfd_error_wrong_format);
328  fail:
329   go32exe_cleanup (abfd);
330   return NULL;
331 }
332 
333 /* Write the stub to the output file, then call coff_write_object_contents.  */
334 
335 static bool
go32exe_write_object_contents(bfd * abfd)336 go32exe_write_object_contents (bfd *abfd)
337 {
338   const bfd_size_type pos = bfd_tell (abfd);
339   const bfd_size_type stubsize = coff_data (abfd)->stub_size;
340 
341   BFD_ASSERT (stubsize != 0);
342 
343   bfd_set_error (bfd_error_system_call);
344 
345   /* Write the stub.  */
346   abfd->origin = 0;
347   if (bfd_seek (abfd, 0, SEEK_SET) != 0)
348     return false;
349   if (bfd_bwrite (coff_data (abfd)->stub, stubsize, abfd) != stubsize)
350     return false;
351 
352   /* Seek back to where we were.  */
353   abfd->origin = stubsize;
354   if (bfd_seek (abfd, pos, SEEK_SET) != 0)
355     return false;
356 
357   return coff_write_object_contents (abfd);
358 }
359 
360 /* mkobject hook.  Called directly through bfd_set_format or via
361    coff_mkobject_hook etc from bfd_check_format.  */
362 
363 static bool
go32exe_mkobject(bfd * abfd)364 go32exe_mkobject (bfd *abfd)
365 {
366   /* Don't output to an archive.  */
367   if (abfd->my_archive != NULL)
368     return false;
369 
370   if (!_bfd_go32_mkobject (abfd))
371     return false;
372 
373   go32exe_create_stub (abfd);
374   if (coff_data (abfd)->stub == NULL)
375     {
376       bfd_release (abfd, coff_data (abfd));
377       return false;
378     }
379   abfd->origin = coff_data (abfd)->stub_size;
380 
381   return true;
382 }
383