(root)/
binutils-2.41/
bfd/
coff-stgo32.c
       1  /* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
       2     Copyright (C) 1997-2023 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
     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
     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
     248  go32exe_cleanup (bfd *abfd)
     249  {
     250    abfd->origin = 0;
     251    coff_object_cleanup (abfd);
     252  
     253    free (go32exe_temp_stub);
     254    go32exe_temp_stub = NULL;
     255    go32exe_temp_stub_size = 0;
     256  }
     257  
     258  /* Check that there is a GO32 stub and read it to go32exe_temp_stub.
     259     Then set abfd->origin so that the COFF image is read at the correct
     260     file offset.  */
     261  
     262  static bfd_cleanup
     263  go32exe_check_format (bfd *abfd)
     264  {
     265    struct external_DOS_hdr filehdr_dos;
     266    uint16_t num_pages;
     267    uint16_t last_page_size;
     268    uint32_t header_end;
     269    bfd_size_type stubsize;
     270  
     271    /* This format can not appear in an archive.  */
     272    if (abfd->origin != 0)
     273      {
     274        bfd_set_error (bfd_error_wrong_format);
     275        return NULL;
     276      }
     277  
     278    bfd_set_error (bfd_error_system_call);
     279  
     280    /* Read in the stub file header, which is a DOS MZ executable.  */
     281    if (bfd_bread (&filehdr_dos, DOS_HDR_SIZE, abfd) != DOS_HDR_SIZE)
     282      goto fail;
     283  
     284    /* Make sure that this is an MZ executable.  */
     285    if (H_GET_16 (abfd, filehdr_dos.e_magic) != IMAGE_DOS_SIGNATURE)
     286      goto fail_format;
     287  
     288    /* Determine the size of the stub  */
     289    num_pages = H_GET_16 (abfd, filehdr_dos.e_cp);
     290    last_page_size = H_GET_16 (abfd, filehdr_dos.e_cblp);
     291    stubsize = num_pages * 512;
     292    if (last_page_size != 0)
     293      stubsize += last_page_size - 512;
     294  
     295    ufile_ptr filesize = bfd_get_file_size (abfd);
     296    if (filesize != 0 && stubsize > filesize)
     297      goto fail_format;
     298  
     299    /* Save now the stub to be used later.  Put the stub data to a temporary
     300       location first as tdata still does not exist.  It may not even
     301       be ever created if we are just checking the file format of ABFD.  */
     302    bfd_seek (abfd, 0, SEEK_SET);
     303    go32exe_temp_stub = bfd_malloc (stubsize);
     304    if (go32exe_temp_stub == NULL)
     305      goto fail;
     306    if (bfd_bread (go32exe_temp_stub, stubsize, abfd) != stubsize)
     307      goto fail;
     308    go32exe_temp_stub_size = stubsize;
     309  
     310    /* Confirm that this is a go32stub.  */
     311    header_end = H_GET_16 (abfd, filehdr_dos.e_cparhdr) * 16UL;
     312    if (go32exe_temp_stub_size < header_end
     313        || go32exe_temp_stub_size - header_end < sizeof "go32stub" - 1
     314        || !startswith (go32exe_temp_stub + header_end, "go32stub"))
     315      goto fail_format;
     316  
     317    /* Set origin to where the COFF header starts and seek there.  */
     318    abfd->origin = stubsize;
     319    if (bfd_seek (abfd, 0, SEEK_SET) != 0)
     320      goto fail;
     321  
     322    /* Call coff_object_p to read the COFF image.  If this fails then the file
     323       must be just a stub with no COFF data attached.  */
     324    bfd_cleanup cleanup = coff_object_p (abfd);
     325    if (cleanup == NULL)
     326      goto fail;
     327    BFD_ASSERT (cleanup == coff_object_cleanup);
     328  
     329    return go32exe_cleanup;
     330  
     331   fail_format:
     332    bfd_set_error (bfd_error_wrong_format);
     333   fail:
     334    go32exe_cleanup (abfd);
     335    return NULL;
     336  }
     337  
     338  /* Write the stub to the output file, then call coff_write_object_contents.  */
     339  
     340  static bool
     341  go32exe_write_object_contents (bfd *abfd)
     342  {
     343    const bfd_size_type pos = bfd_tell (abfd);
     344    const bfd_size_type stubsize = coff_data (abfd)->stub_size;
     345  
     346    BFD_ASSERT (stubsize != 0);
     347  
     348    bfd_set_error (bfd_error_system_call);
     349  
     350    /* Write the stub.  */
     351    abfd->origin = 0;
     352    if (bfd_seek (abfd, 0, SEEK_SET) != 0)
     353      return false;
     354    if (bfd_bwrite (coff_data (abfd)->stub, stubsize, abfd) != stubsize)
     355      return false;
     356  
     357    /* Seek back to where we were.  */
     358    abfd->origin = stubsize;
     359    if (bfd_seek (abfd, pos, SEEK_SET) != 0)
     360      return false;
     361  
     362    return coff_write_object_contents (abfd);
     363  }
     364  
     365  /* mkobject hook.  Called directly through bfd_set_format or via
     366     coff_mkobject_hook etc from bfd_check_format.  */
     367  
     368  static bool
     369  go32exe_mkobject (bfd *abfd)
     370  {
     371    /* Don't output to an archive.  */
     372    if (abfd->my_archive != NULL)
     373      return false;
     374  
     375    if (!_bfd_go32_mkobject (abfd))
     376      return false;
     377  
     378    go32exe_create_stub (abfd);
     379    if (coff_data (abfd)->stub == NULL)
     380      {
     381        bfd_release (abfd, coff_data (abfd));
     382        return false;
     383      }
     384    abfd->origin = coff_data (abfd)->stub_size;
     385  
     386    return true;
     387  }