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