Home | History | Annotate | Line # | Download | only in libiberty
      1  1.1  mrg /* simple-object-coff.c -- routines to manipulate COFF object files.
      2  1.9  mrg    Copyright (C) 2010-2022 Free Software Foundation, Inc.
      3  1.1  mrg    Written by Ian Lance Taylor, Google.
      4  1.1  mrg 
      5  1.1  mrg This program is free software; you can redistribute it and/or modify it
      6  1.1  mrg under the terms of the GNU General Public License as published by the
      7  1.1  mrg Free Software Foundation; either version 2, or (at your option) any
      8  1.1  mrg later version.
      9  1.1  mrg 
     10  1.1  mrg This program is distributed in the hope that it will be useful,
     11  1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1  mrg GNU General Public License for more details.
     14  1.1  mrg 
     15  1.1  mrg You should have received a copy of the GNU General Public License
     16  1.1  mrg along with this program; if not, write to the Free Software
     17  1.1  mrg Foundation, 51 Franklin Street - Fifth Floor,
     18  1.1  mrg Boston, MA 02110-1301, USA.  */
     19  1.1  mrg 
     20  1.1  mrg #include "config.h"
     21  1.1  mrg #include "libiberty.h"
     22  1.1  mrg #include "simple-object.h"
     23  1.1  mrg 
     24  1.1  mrg #include <errno.h>
     25  1.1  mrg #include <stddef.h>
     26  1.1  mrg 
     27  1.1  mrg #ifdef HAVE_STDLIB_H
     28  1.1  mrg #include <stdlib.h>
     29  1.1  mrg #endif
     30  1.1  mrg 
     31  1.1  mrg #ifdef HAVE_STDINT_H
     32  1.1  mrg #include <stdint.h>
     33  1.1  mrg #endif
     34  1.1  mrg 
     35  1.1  mrg #ifdef HAVE_STRING_H
     36  1.1  mrg #include <string.h>
     37  1.1  mrg #endif
     38  1.1  mrg 
     39  1.1  mrg #ifdef HAVE_INTTYPES_H
     40  1.1  mrg #include <inttypes.h>
     41  1.1  mrg #endif
     42  1.1  mrg 
     43  1.1  mrg #include "simple-object-common.h"
     44  1.1  mrg 
     45  1.1  mrg /* COFF structures and constants.  */
     46  1.1  mrg 
     47  1.1  mrg /* COFF file header.  */
     48  1.1  mrg 
     49  1.1  mrg struct external_filehdr
     50  1.1  mrg {
     51  1.1  mrg   unsigned char f_magic[2];	/* magic number			*/
     52  1.1  mrg   unsigned char f_nscns[2];	/* number of sections		*/
     53  1.1  mrg   unsigned char f_timdat[4];	/* time & date stamp		*/
     54  1.1  mrg   unsigned char f_symptr[4];	/* file pointer to symtab	*/
     55  1.1  mrg   unsigned char f_nsyms[4];	/* number of symtab entries	*/
     56  1.1  mrg   unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
     57  1.1  mrg   unsigned char f_flags[2];	/* flags			*/
     58  1.1  mrg };
     59  1.1  mrg 
     60  1.1  mrg /* Bits for filehdr f_flags field.  */
     61  1.1  mrg 
     62  1.1  mrg #define F_EXEC			(0x0002)
     63  1.1  mrg #define IMAGE_FILE_SYSTEM	(0x1000)
     64  1.1  mrg #define IMAGE_FILE_DLL		(0x2000)
     65  1.1  mrg 
     66  1.1  mrg /* COFF section header.  */
     67  1.1  mrg 
     68  1.1  mrg struct external_scnhdr
     69  1.1  mrg {
     70  1.1  mrg   unsigned char s_name[8];	/* section name				*/
     71  1.1  mrg   unsigned char s_paddr[4];	/* physical address, aliased s_nlib 	*/
     72  1.1  mrg   unsigned char s_vaddr[4];	/* virtual address			*/
     73  1.1  mrg   unsigned char s_size[4];	/* section size				*/
     74  1.1  mrg   unsigned char s_scnptr[4];	/* file ptr to raw data for section 	*/
     75  1.1  mrg   unsigned char s_relptr[4];	/* file ptr to relocation		*/
     76  1.1  mrg   unsigned char s_lnnoptr[4];	/* file ptr to line numbers		*/
     77  1.1  mrg   unsigned char s_nreloc[2];	/* number of relocation entries		*/
     78  1.1  mrg   unsigned char s_nlnno[2];	/* number of line number entries	*/
     79  1.1  mrg   unsigned char s_flags[4];	/* flags				*/
     80  1.1  mrg };
     81  1.1  mrg 
     82  1.1  mrg /* The length of the s_name field in struct external_scnhdr.  */
     83  1.1  mrg 
     84  1.1  mrg #define SCNNMLEN (8)
     85  1.1  mrg 
     86  1.1  mrg /* Bits for scnhdr s_flags field.  This includes some bits defined
     87  1.1  mrg    only for PE.  This may need to be moved into coff_magic.  */
     88  1.1  mrg 
     89  1.1  mrg #define STYP_DATA			(1 << 6)
     90  1.1  mrg #define IMAGE_SCN_MEM_DISCARDABLE	(1 << 25)
     91  1.1  mrg #define IMAGE_SCN_MEM_SHARED		(1 << 28)
     92  1.1  mrg #define IMAGE_SCN_MEM_READ		(1 << 30)
     93  1.1  mrg 
     94  1.1  mrg #define IMAGE_SCN_ALIGN_POWER_BIT_POS	     20
     95  1.1  mrg #define IMAGE_SCN_ALIGN_POWER_CONST(val)     \
     96  1.1  mrg   (((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS)
     97  1.1  mrg 
     98  1.1  mrg /* COFF symbol table entry.  */
     99  1.1  mrg 
    100  1.1  mrg #define E_SYMNMLEN	8	/* # characters in a symbol name	*/
    101  1.1  mrg 
    102  1.1  mrg struct external_syment
    103  1.1  mrg {
    104  1.1  mrg   union
    105  1.1  mrg   {
    106  1.1  mrg     unsigned char e_name[E_SYMNMLEN];
    107  1.1  mrg 
    108  1.1  mrg     struct
    109  1.1  mrg     {
    110  1.1  mrg       unsigned char e_zeroes[4];
    111  1.1  mrg       unsigned char e_offset[4];
    112  1.1  mrg     } e;
    113  1.1  mrg   } e;
    114  1.1  mrg 
    115  1.1  mrg   unsigned char e_value[4];
    116  1.1  mrg   unsigned char e_scnum[2];
    117  1.1  mrg   unsigned char e_type[2];
    118  1.1  mrg   unsigned char e_sclass[1];
    119  1.1  mrg   unsigned char e_numaux[1];
    120  1.1  mrg };
    121  1.1  mrg 
    122  1.1  mrg /* Length allowed for filename in aux sym format 4.  */
    123  1.1  mrg 
    124  1.1  mrg #define E_FILNMLEN	18
    125  1.1  mrg 
    126  1.1  mrg /* Omits x_sym and other unused variants.  */
    127  1.1  mrg 
    128  1.1  mrg union external_auxent
    129  1.1  mrg {
    130  1.1  mrg   /* Aux sym format 4: file.  */
    131  1.1  mrg   union
    132  1.1  mrg   {
    133  1.1  mrg     char x_fname[E_FILNMLEN];
    134  1.1  mrg     struct
    135  1.1  mrg     {
    136  1.1  mrg       unsigned char x_zeroes[4];
    137  1.1  mrg       unsigned char x_offset[4];
    138  1.1  mrg     } x_n;
    139  1.1  mrg   } x_file;
    140  1.1  mrg   /* Aux sym format 5: section.  */
    141  1.1  mrg   struct
    142  1.1  mrg   {
    143  1.1  mrg     unsigned char x_scnlen[4];		/* section length		*/
    144  1.1  mrg     unsigned char x_nreloc[2];		/* # relocation entries		*/
    145  1.1  mrg     unsigned char x_nlinno[2];		/* # line numbers		*/
    146  1.1  mrg     unsigned char x_checksum[4];	/* section COMDAT checksum	*/
    147  1.1  mrg     unsigned char x_associated[2];	/* COMDAT assoc section index	*/
    148  1.1  mrg     unsigned char x_comdat[1];		/* COMDAT selection number	*/
    149  1.1  mrg   } x_scn;
    150  1.1  mrg };
    151  1.1  mrg 
    152  1.1  mrg /* Symbol-related constants.  */
    153  1.1  mrg 
    154  1.1  mrg #define IMAGE_SYM_DEBUG		(-2)
    155  1.1  mrg #define IMAGE_SYM_TYPE_NULL	(0)
    156  1.1  mrg #define IMAGE_SYM_DTYPE_NULL	(0)
    157  1.1  mrg #define IMAGE_SYM_CLASS_STATIC	(3)
    158  1.1  mrg #define IMAGE_SYM_CLASS_FILE	(103)
    159  1.1  mrg 
    160  1.1  mrg #define IMAGE_SYM_TYPE \
    161  1.1  mrg   ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
    162  1.1  mrg 
    163  1.1  mrg /* Private data for an simple_object_read.  */
    164  1.1  mrg 
    165  1.1  mrg struct simple_object_coff_read
    166  1.1  mrg {
    167  1.1  mrg   /* Magic number.  */
    168  1.1  mrg   unsigned short magic;
    169  1.1  mrg   /* Whether the file is big-endian.  */
    170  1.1  mrg   unsigned char is_big_endian;
    171  1.1  mrg   /* Number of sections.  */
    172  1.1  mrg   unsigned short nscns;
    173  1.1  mrg   /* File offset of symbol table.  */
    174  1.1  mrg   off_t symptr;
    175  1.1  mrg   /* Number of symbol table entries.  */
    176  1.1  mrg   unsigned int nsyms;
    177  1.1  mrg   /* Flags.  */
    178  1.1  mrg   unsigned short flags;
    179  1.1  mrg   /* Offset of section headers in file.  */
    180  1.1  mrg   off_t scnhdr_offset;
    181  1.1  mrg };
    182  1.1  mrg 
    183  1.1  mrg /* Private data for an simple_object_attributes.  */
    184  1.1  mrg 
    185  1.1  mrg struct simple_object_coff_attributes
    186  1.1  mrg {
    187  1.1  mrg   /* Magic number.  */
    188  1.1  mrg   unsigned short magic;
    189  1.1  mrg   /* Whether the file is big-endian.  */
    190  1.1  mrg   unsigned char is_big_endian;
    191  1.1  mrg   /* Flags.  */
    192  1.1  mrg   unsigned short flags;
    193  1.1  mrg };
    194  1.1  mrg 
    195  1.1  mrg /* There is no magic number which indicates a COFF file as opposed to
    196  1.1  mrg    any other sort of file.  Instead, each COFF file starts with a
    197  1.1  mrg    two-byte magic number which also indicates the type of the target.
    198  1.1  mrg    This struct holds a magic number as well as characteristics of that
    199  1.1  mrg    COFF format.  */
    200  1.1  mrg 
    201  1.1  mrg struct coff_magic_struct
    202  1.1  mrg {
    203  1.1  mrg   /* Magic number.  */
    204  1.1  mrg   unsigned short magic;
    205  1.1  mrg   /* Whether this magic number is for a big-endian file.  */
    206  1.1  mrg   unsigned char is_big_endian;
    207  1.1  mrg   /* Flag bits, in the f_flags fields, which indicates that this file
    208  1.1  mrg      is not a relocatable object file.  There is no flag which
    209  1.1  mrg      specifically indicates a relocatable object file, it is only
    210  1.1  mrg      implied by the absence of these flags.  */
    211  1.1  mrg   unsigned short non_object_flags;
    212  1.1  mrg };
    213  1.1  mrg 
    214  1.1  mrg /* This is a list of the COFF magic numbers which we recognize, namely
    215  1.1  mrg    the ones used on Windows.  More can be added as needed.  */
    216  1.1  mrg 
    217  1.1  mrg static const struct coff_magic_struct coff_magic[] =
    218  1.1  mrg {
    219  1.1  mrg   /* i386.  */
    220  1.1  mrg   { 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
    221  1.1  mrg   /* x86_64.  */
    222  1.1  mrg   { 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
    223  1.1  mrg };
    224  1.1  mrg 
    225  1.1  mrg /* See if we have a COFF file.  */
    226  1.1  mrg 
    227  1.1  mrg static void *
    228  1.1  mrg simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
    229  1.1  mrg 			  int descriptor, off_t offset,
    230  1.1  mrg 			  const char *segment_name ATTRIBUTE_UNUSED,
    231  1.1  mrg 			  const char **errmsg, int *err)
    232  1.1  mrg {
    233  1.1  mrg   size_t c;
    234  1.1  mrg   unsigned short magic_big;
    235  1.1  mrg   unsigned short magic_little;
    236  1.1  mrg   unsigned short magic;
    237  1.1  mrg   size_t i;
    238  1.1  mrg   int is_big_endian;
    239  1.1  mrg   unsigned short (*fetch_16) (const unsigned char *);
    240  1.1  mrg   unsigned int (*fetch_32) (const unsigned char *);
    241  1.1  mrg   unsigned char hdrbuf[sizeof (struct external_filehdr)];
    242  1.1  mrg   unsigned short flags;
    243  1.1  mrg   struct simple_object_coff_read *ocr;
    244  1.1  mrg 
    245  1.1  mrg   c = sizeof (coff_magic) / sizeof (coff_magic[0]);
    246  1.1  mrg   magic_big = simple_object_fetch_big_16 (header);
    247  1.1  mrg   magic_little = simple_object_fetch_little_16 (header);
    248  1.1  mrg   for (i = 0; i < c; ++i)
    249  1.1  mrg     {
    250  1.1  mrg       if (coff_magic[i].is_big_endian
    251  1.1  mrg 	  ? coff_magic[i].magic == magic_big
    252  1.1  mrg 	  : coff_magic[i].magic == magic_little)
    253  1.1  mrg 	break;
    254  1.1  mrg     }
    255  1.1  mrg   if (i >= c)
    256  1.1  mrg     {
    257  1.1  mrg       *errmsg = NULL;
    258  1.1  mrg       *err = 0;
    259  1.1  mrg       return NULL;
    260  1.1  mrg     }
    261  1.1  mrg   is_big_endian = coff_magic[i].is_big_endian;
    262  1.1  mrg 
    263  1.1  mrg   magic = is_big_endian ? magic_big : magic_little;
    264  1.1  mrg   fetch_16 = (is_big_endian
    265  1.1  mrg 	      ? simple_object_fetch_big_16
    266  1.1  mrg 	      : simple_object_fetch_little_16);
    267  1.1  mrg   fetch_32 = (is_big_endian
    268  1.1  mrg 	      ? simple_object_fetch_big_32
    269  1.1  mrg 	      : simple_object_fetch_little_32);
    270  1.1  mrg 
    271  1.1  mrg   if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
    272  1.1  mrg 				    errmsg, err))
    273  1.1  mrg     return NULL;
    274  1.1  mrg 
    275  1.1  mrg   flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
    276  1.1  mrg   if ((flags & coff_magic[i].non_object_flags) != 0)
    277  1.1  mrg     {
    278  1.1  mrg       *errmsg = "not relocatable object file";
    279  1.1  mrg       *err = 0;
    280  1.1  mrg       return NULL;
    281  1.1  mrg     }
    282  1.1  mrg 
    283  1.1  mrg   ocr = XNEW (struct simple_object_coff_read);
    284  1.1  mrg   ocr->magic = magic;
    285  1.1  mrg   ocr->is_big_endian = is_big_endian;
    286  1.1  mrg   ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
    287  1.1  mrg   ocr->symptr = fetch_32 (hdrbuf
    288  1.1  mrg 			  + offsetof (struct external_filehdr, f_symptr));
    289  1.1  mrg   ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
    290  1.1  mrg   ocr->flags = flags;
    291  1.1  mrg   ocr->scnhdr_offset = (sizeof (struct external_filehdr)
    292  1.1  mrg 			+ fetch_16 (hdrbuf + offsetof (struct external_filehdr,
    293  1.1  mrg 						       f_opthdr)));
    294  1.1  mrg 
    295  1.1  mrg   return (void *) ocr;
    296  1.1  mrg }
    297  1.1  mrg 
    298  1.1  mrg /* Read the string table in a COFF file.  */
    299  1.1  mrg 
    300  1.1  mrg static char *
    301  1.1  mrg simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
    302  1.1  mrg 				const char **errmsg, int *err)
    303  1.1  mrg {
    304  1.1  mrg   struct simple_object_coff_read *ocr =
    305  1.1  mrg     (struct simple_object_coff_read *) sobj->data;
    306  1.1  mrg   off_t strtab_offset;
    307  1.1  mrg   unsigned char strsizebuf[4];
    308  1.1  mrg   size_t strsize;
    309  1.1  mrg   char *strtab;
    310  1.1  mrg 
    311  1.1  mrg   strtab_offset = sobj->offset + ocr->symptr
    312  1.1  mrg 		  + ocr->nsyms * sizeof (struct external_syment);
    313  1.1  mrg   if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
    314  1.1  mrg 				    strsizebuf, 4, errmsg, err))
    315  1.1  mrg     return NULL;
    316  1.1  mrg   strsize = (ocr->is_big_endian
    317  1.1  mrg 	     ? simple_object_fetch_big_32 (strsizebuf)
    318  1.1  mrg 	     : simple_object_fetch_little_32 (strsizebuf));
    319  1.1  mrg   strtab = XNEWVEC (char, strsize);
    320  1.1  mrg   if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
    321  1.1  mrg 				    (unsigned char *) strtab, strsize, errmsg,
    322  1.1  mrg 				    err))
    323  1.1  mrg     {
    324  1.1  mrg       XDELETEVEC (strtab);
    325  1.1  mrg       return NULL;
    326  1.1  mrg     }
    327  1.1  mrg   *strtab_size = strsize;
    328  1.1  mrg   return strtab;
    329  1.1  mrg }
    330  1.1  mrg 
    331  1.1  mrg /* Find all sections in a COFF file.  */
    332  1.1  mrg 
    333  1.1  mrg static const char *
    334  1.1  mrg simple_object_coff_find_sections (simple_object_read *sobj,
    335  1.1  mrg 				  int (*pfn) (void *, const char *,
    336  1.1  mrg 					      off_t offset, off_t length),
    337  1.1  mrg 				  void *data,
    338  1.1  mrg 				  int *err)
    339  1.1  mrg {
    340  1.1  mrg   struct simple_object_coff_read *ocr =
    341  1.1  mrg     (struct simple_object_coff_read *) sobj->data;
    342  1.1  mrg   size_t scnhdr_size;
    343  1.1  mrg   unsigned char *scnbuf;
    344  1.1  mrg   const char *errmsg;
    345  1.1  mrg   unsigned int (*fetch_32) (const unsigned char *);
    346  1.1  mrg   unsigned int nscns;
    347  1.1  mrg   char *strtab;
    348  1.1  mrg   size_t strtab_size;
    349  1.1  mrg   unsigned int i;
    350  1.1  mrg 
    351  1.1  mrg   scnhdr_size = sizeof (struct external_scnhdr);
    352  1.1  mrg   scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
    353  1.1  mrg   if (!simple_object_internal_read (sobj->descriptor,
    354  1.1  mrg 				    sobj->offset + ocr->scnhdr_offset,
    355  1.1  mrg 				    scnbuf, scnhdr_size * ocr->nscns, &errmsg,
    356  1.1  mrg 				    err))
    357  1.1  mrg     {
    358  1.1  mrg       XDELETEVEC (scnbuf);
    359  1.1  mrg       return errmsg;
    360  1.1  mrg     }
    361  1.1  mrg 
    362  1.1  mrg   fetch_32 = (ocr->is_big_endian
    363  1.1  mrg 	      ? simple_object_fetch_big_32
    364  1.1  mrg 	      : simple_object_fetch_little_32);
    365  1.1  mrg 
    366  1.1  mrg   nscns = ocr->nscns;
    367  1.1  mrg   strtab = NULL;
    368  1.1  mrg   strtab_size = 0;
    369  1.1  mrg   for (i = 0; i < nscns; ++i)
    370  1.1  mrg     {
    371  1.1  mrg       unsigned char *scnhdr;
    372  1.1  mrg       unsigned char *scnname;
    373  1.1  mrg       char namebuf[SCNNMLEN + 1];
    374  1.1  mrg       char *name;
    375  1.1  mrg       off_t scnptr;
    376  1.1  mrg       unsigned int size;
    377  1.1  mrg 
    378  1.1  mrg       scnhdr = scnbuf + i * scnhdr_size;
    379  1.1  mrg       scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
    380  1.1  mrg       memcpy (namebuf, scnname, SCNNMLEN);
    381  1.1  mrg       namebuf[SCNNMLEN] = '\0';
    382  1.1  mrg       name = &namebuf[0];
    383  1.1  mrg       if (namebuf[0] == '/')
    384  1.1  mrg 	{
    385  1.1  mrg 	  size_t strindex;
    386  1.1  mrg 	  char *end;
    387  1.1  mrg 
    388  1.1  mrg 	  strindex = strtol (namebuf + 1, &end, 10);
    389  1.1  mrg 	  if (*end == '\0')
    390  1.1  mrg 	    {
    391  1.1  mrg 	      /* The real section name is found in the string
    392  1.1  mrg 		 table.  */
    393  1.1  mrg 	      if (strtab == NULL)
    394  1.1  mrg 		{
    395  1.1  mrg 		  strtab = simple_object_coff_read_strtab (sobj,
    396  1.1  mrg 							   &strtab_size,
    397  1.1  mrg 							   &errmsg, err);
    398  1.1  mrg 		  if (strtab == NULL)
    399  1.1  mrg 		    {
    400  1.1  mrg 		      XDELETEVEC (scnbuf);
    401  1.1  mrg 		      return errmsg;
    402  1.1  mrg 		    }
    403  1.1  mrg 		}
    404  1.1  mrg 
    405  1.1  mrg 	      if (strindex < 4 || strindex >= strtab_size)
    406  1.1  mrg 		{
    407  1.1  mrg 		  XDELETEVEC (strtab);
    408  1.1  mrg 		  XDELETEVEC (scnbuf);
    409  1.1  mrg 		  *err = 0;
    410  1.1  mrg 		  return "section string index out of range";
    411  1.1  mrg 		}
    412  1.1  mrg 
    413  1.1  mrg 	      name = strtab + strindex;
    414  1.1  mrg 	    }
    415  1.1  mrg 	}
    416  1.1  mrg 
    417  1.1  mrg       scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
    418  1.1  mrg       size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));
    419  1.1  mrg 
    420  1.1  mrg       if (!(*pfn) (data, name, scnptr, size))
    421  1.1  mrg 	break;
    422  1.1  mrg     }
    423  1.1  mrg 
    424  1.1  mrg   if (strtab != NULL)
    425  1.1  mrg     XDELETEVEC (strtab);
    426  1.1  mrg   XDELETEVEC (scnbuf);
    427  1.1  mrg 
    428  1.1  mrg   return NULL;
    429  1.1  mrg }
    430  1.1  mrg 
    431  1.1  mrg /* Fetch the attributes for an simple_object_read.  */
    432  1.1  mrg 
    433  1.1  mrg static void *
    434  1.1  mrg simple_object_coff_fetch_attributes (simple_object_read *sobj,
    435  1.1  mrg 				     const char **errmsg ATTRIBUTE_UNUSED,
    436  1.1  mrg 				     int *err ATTRIBUTE_UNUSED)
    437  1.1  mrg {
    438  1.1  mrg   struct simple_object_coff_read *ocr =
    439  1.1  mrg     (struct simple_object_coff_read *) sobj->data;
    440  1.1  mrg   struct simple_object_coff_attributes *ret;
    441  1.1  mrg 
    442  1.1  mrg   ret = XNEW (struct simple_object_coff_attributes);
    443  1.1  mrg   ret->magic = ocr->magic;
    444  1.1  mrg   ret->is_big_endian = ocr->is_big_endian;
    445  1.1  mrg   ret->flags = ocr->flags;
    446  1.1  mrg   return ret;
    447  1.1  mrg }
    448  1.1  mrg 
    449  1.1  mrg /* Release the private data for an simple_object_read.  */
    450  1.1  mrg 
    451  1.1  mrg static void
    452  1.1  mrg simple_object_coff_release_read (void *data)
    453  1.1  mrg {
    454  1.1  mrg   XDELETE (data);
    455  1.1  mrg }
    456  1.1  mrg 
    457  1.1  mrg /* Compare two attributes structures.  */
    458  1.1  mrg 
    459  1.1  mrg static const char *
    460  1.1  mrg simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err)
    461  1.1  mrg {
    462  1.1  mrg   struct simple_object_coff_attributes *to =
    463  1.1  mrg     (struct simple_object_coff_attributes *) todata;
    464  1.1  mrg   struct simple_object_coff_attributes *from =
    465  1.1  mrg     (struct simple_object_coff_attributes *) fromdata;
    466  1.1  mrg 
    467  1.1  mrg   if (to->magic != from->magic || to->is_big_endian != from->is_big_endian)
    468  1.1  mrg     {
    469  1.1  mrg       *err = 0;
    470  1.1  mrg       return "COFF object format mismatch";
    471  1.1  mrg     }
    472  1.1  mrg   return NULL;
    473  1.1  mrg }
    474  1.1  mrg 
    475  1.1  mrg /* Release the private data for an attributes structure.  */
    476  1.1  mrg 
    477  1.1  mrg static void
    478  1.1  mrg simple_object_coff_release_attributes (void *data)
    479  1.1  mrg {
    480  1.1  mrg   XDELETE (data);
    481  1.1  mrg }
    482  1.1  mrg 
    483  1.1  mrg /* Prepare to write out a file.  */
    484  1.1  mrg 
    485  1.1  mrg static void *
    486  1.1  mrg simple_object_coff_start_write (void *attributes_data,
    487  1.1  mrg 				const char **errmsg ATTRIBUTE_UNUSED,
    488  1.1  mrg 				int *err ATTRIBUTE_UNUSED)
    489  1.1  mrg {
    490  1.1  mrg   struct simple_object_coff_attributes *attrs =
    491  1.1  mrg     (struct simple_object_coff_attributes *) attributes_data;
    492  1.1  mrg   struct simple_object_coff_attributes *ret;
    493  1.1  mrg 
    494  1.1  mrg   /* We're just going to record the attributes, but we need to make a
    495  1.1  mrg      copy because the user may delete them.  */
    496  1.1  mrg   ret = XNEW (struct simple_object_coff_attributes);
    497  1.1  mrg   *ret = *attrs;
    498  1.1  mrg   return ret;
    499  1.1  mrg }
    500  1.1  mrg 
    501  1.1  mrg /* Write out a COFF filehdr.  */
    502  1.1  mrg 
    503  1.1  mrg static int
    504  1.1  mrg simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor,
    505  1.1  mrg 				  unsigned int nscns, size_t symtab_offset,
    506  1.1  mrg 				  unsigned int nsyms, const char **errmsg,
    507  1.1  mrg 				  int *err)
    508  1.1  mrg {
    509  1.1  mrg   struct simple_object_coff_attributes *attrs =
    510  1.1  mrg     (struct simple_object_coff_attributes *) sobj->data;
    511  1.1  mrg   unsigned char hdrbuf[sizeof (struct external_filehdr)];
    512  1.1  mrg   unsigned char *hdr;
    513  1.1  mrg   void (*set_16) (unsigned char *, unsigned short);
    514  1.1  mrg   void (*set_32) (unsigned char *, unsigned int);
    515  1.1  mrg 
    516  1.1  mrg   hdr = &hdrbuf[0];
    517  1.1  mrg 
    518  1.1  mrg   set_16 = (attrs->is_big_endian
    519  1.1  mrg 	    ? simple_object_set_big_16
    520  1.1  mrg 	    : simple_object_set_little_16);
    521  1.1  mrg   set_32 = (attrs->is_big_endian
    522  1.1  mrg 	    ? simple_object_set_big_32
    523  1.1  mrg 	    : simple_object_set_little_32);
    524  1.1  mrg 
    525  1.1  mrg   memset (hdr, 0, sizeof (struct external_filehdr));
    526  1.1  mrg 
    527  1.1  mrg   set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
    528  1.1  mrg   set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
    529  1.1  mrg   /* f_timdat left as zero.  */
    530  1.1  mrg   set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
    531  1.1  mrg   set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
    532  1.1  mrg   /* f_opthdr left as zero.  */
    533  1.1  mrg   set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
    534  1.1  mrg 
    535  1.1  mrg   return simple_object_internal_write (descriptor, 0, hdrbuf,
    536  1.1  mrg 				       sizeof (struct external_filehdr),
    537  1.1  mrg 				       errmsg, err);
    538  1.1  mrg }
    539  1.1  mrg 
    540  1.1  mrg /* Write out a COFF section header.  */
    541  1.1  mrg 
    542  1.1  mrg static int
    543  1.1  mrg simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor,
    544  1.1  mrg 				 const char *name, size_t *name_offset,
    545  1.1  mrg 				 off_t scnhdr_offset, size_t scnsize,
    546  1.1  mrg 				 off_t offset, unsigned int align,
    547  1.1  mrg 				 const char **errmsg, int *err)
    548  1.1  mrg {
    549  1.1  mrg   struct simple_object_coff_attributes *attrs =
    550  1.1  mrg     (struct simple_object_coff_attributes *) sobj->data;
    551  1.1  mrg   void (*set_32) (unsigned char *, unsigned int);
    552  1.1  mrg   unsigned char hdrbuf[sizeof (struct external_scnhdr)];
    553  1.1  mrg   unsigned char *hdr;
    554  1.1  mrg   size_t namelen;
    555  1.1  mrg   unsigned int flags;
    556  1.1  mrg 
    557  1.1  mrg   set_32 = (attrs->is_big_endian
    558  1.1  mrg 	    ? simple_object_set_big_32
    559  1.1  mrg 	    : simple_object_set_little_32);
    560  1.1  mrg 
    561  1.1  mrg   memset (hdrbuf, 0, sizeof hdrbuf);
    562  1.1  mrg   hdr = &hdrbuf[0];
    563  1.1  mrg 
    564  1.1  mrg   namelen = strlen (name);
    565  1.1  mrg   if (namelen <= SCNNMLEN)
    566  1.1  mrg     strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
    567  1.1  mrg 	     SCNNMLEN);
    568  1.1  mrg   else
    569  1.1  mrg     {
    570  1.1  mrg       snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
    571  1.1  mrg 		SCNNMLEN, "/%lu", (unsigned long) *name_offset);
    572  1.1  mrg       *name_offset += namelen + 1;
    573  1.1  mrg     }
    574  1.1  mrg 
    575  1.1  mrg   /* s_paddr left as zero.  */
    576  1.1  mrg   /* s_vaddr left as zero.  */
    577  1.1  mrg   set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
    578  1.1  mrg   set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
    579  1.1  mrg   /* s_relptr left as zero.  */
    580  1.1  mrg   /* s_lnnoptr left as zero.  */
    581  1.1  mrg   /* s_nreloc left as zero.  */
    582  1.1  mrg   /* s_nlnno left as zero.  */
    583  1.1  mrg   flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
    584  1.1  mrg 	   | IMAGE_SCN_MEM_READ);
    585  1.1  mrg   /* PE can represent alignment up to 13.  */
    586  1.1  mrg   if (align > 13)
    587  1.1  mrg     align = 13;
    588  1.1  mrg   flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
    589  1.1  mrg   set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);
    590  1.1  mrg 
    591  1.1  mrg   return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
    592  1.1  mrg 				       sizeof (struct external_scnhdr),
    593  1.1  mrg 				       errmsg, err);
    594  1.1  mrg }
    595  1.1  mrg 
    596  1.1  mrg /* Write out a complete COFF file.  */
    597  1.1  mrg 
    598  1.1  mrg static const char *
    599  1.1  mrg simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor,
    600  1.1  mrg 				  int *err)
    601  1.1  mrg {
    602  1.1  mrg   struct simple_object_coff_attributes *attrs =
    603  1.1  mrg     (struct simple_object_coff_attributes *) sobj->data;
    604  1.1  mrg   unsigned int nscns, secnum;
    605  1.1  mrg   simple_object_write_section *section;
    606  1.1  mrg   off_t scnhdr_offset;
    607  1.1  mrg   size_t symtab_offset;
    608  1.1  mrg   off_t secsym_offset;
    609  1.1  mrg   unsigned int nsyms;
    610  1.1  mrg   size_t offset;
    611  1.1  mrg   size_t name_offset;
    612  1.1  mrg   const char *errmsg;
    613  1.1  mrg   unsigned char strsizebuf[4];
    614  1.1  mrg   /* The interface doesn't give us access to the name of the input file
    615  1.1  mrg      yet.  We want to use its basename for the FILE symbol.  This is
    616  1.1  mrg      what 'gas' uses when told to assemble from stdin.  */
    617  1.1  mrg   const char *source_filename = "fake";
    618  1.1  mrg   size_t sflen;
    619  1.1  mrg   union
    620  1.1  mrg   {
    621  1.1  mrg     struct external_syment sym;
    622  1.1  mrg     union external_auxent aux;
    623  1.1  mrg   } syms[2];
    624  1.1  mrg   void (*set_16) (unsigned char *, unsigned short);
    625  1.1  mrg   void (*set_32) (unsigned char *, unsigned int);
    626  1.1  mrg 
    627  1.1  mrg   set_16 = (attrs->is_big_endian
    628  1.1  mrg 	    ? simple_object_set_big_16
    629  1.1  mrg 	    : simple_object_set_little_16);
    630  1.1  mrg   set_32 = (attrs->is_big_endian
    631  1.1  mrg 	    ? simple_object_set_big_32
    632  1.1  mrg 	    : simple_object_set_little_32);
    633  1.1  mrg 
    634  1.1  mrg   nscns = 0;
    635  1.1  mrg   for (section = sobj->sections; section != NULL; section = section->next)
    636  1.1  mrg     ++nscns;
    637  1.1  mrg 
    638  1.1  mrg   scnhdr_offset = sizeof (struct external_filehdr);
    639  1.1  mrg   offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
    640  1.1  mrg   name_offset = 4;
    641  1.1  mrg   for (section = sobj->sections; section != NULL; section = section->next)
    642  1.1  mrg     {
    643  1.1  mrg       size_t mask;
    644  1.1  mrg       size_t new_offset;
    645  1.1  mrg       size_t scnsize;
    646  1.1  mrg       struct simple_object_write_section_buffer *buffer;
    647  1.1  mrg 
    648  1.1  mrg       mask = (1U << section->align) - 1;
    649  1.1  mrg       new_offset = offset & mask;
    650  1.1  mrg       new_offset &= ~ mask;
    651  1.1  mrg       while (new_offset > offset)
    652  1.1  mrg 	{
    653  1.1  mrg 	  unsigned char zeroes[16];
    654  1.1  mrg 	  size_t write;
    655  1.1  mrg 
    656  1.1  mrg 	  memset (zeroes, 0, sizeof zeroes);
    657  1.1  mrg 	  write = new_offset - offset;
    658  1.1  mrg 	  if (write > sizeof zeroes)
    659  1.1  mrg 	    write = sizeof zeroes;
    660  1.1  mrg 	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
    661  1.1  mrg 					     &errmsg, err))
    662  1.1  mrg 	    return errmsg;
    663  1.1  mrg 	}
    664  1.1  mrg 
    665  1.1  mrg       scnsize = 0;
    666  1.1  mrg       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
    667  1.1  mrg 	{
    668  1.1  mrg 	  if (!simple_object_internal_write (descriptor, offset + scnsize,
    669  1.1  mrg 					     ((const unsigned char *)
    670  1.1  mrg 					      buffer->buffer),
    671  1.1  mrg 					     buffer->size, &errmsg, err))
    672  1.1  mrg 	    return errmsg;
    673  1.1  mrg 	  scnsize += buffer->size;
    674  1.1  mrg 	}
    675  1.1  mrg 
    676  1.1  mrg       if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name,
    677  1.1  mrg 					    &name_offset, scnhdr_offset,
    678  1.1  mrg 					    scnsize, offset, section->align,
    679  1.1  mrg 					    &errmsg, err))
    680  1.1  mrg 	return errmsg;
    681  1.1  mrg 
    682  1.1  mrg       scnhdr_offset += sizeof (struct external_scnhdr);
    683  1.1  mrg       offset += scnsize;
    684  1.1  mrg     }
    685  1.1  mrg 
    686  1.1  mrg   /* Symbol table is always half-word aligned.  */
    687  1.1  mrg   offset += (offset & 1);
    688  1.1  mrg   /* There is a file symbol and a section symbol per section,
    689  1.1  mrg      and each of these has a single auxiliary symbol following.  */
    690  1.1  mrg   nsyms = 2 * (nscns + 1);
    691  1.1  mrg   symtab_offset = offset;
    692  1.1  mrg   /* Advance across space reserved for symbol table to locate
    693  1.1  mrg      start of string table.  */
    694  1.1  mrg   offset += nsyms * sizeof (struct external_syment);
    695  1.1  mrg 
    696  1.1  mrg   /* Write out file symbol.  */
    697  1.1  mrg   memset (&syms[0], 0, sizeof (syms));
    698  1.1  mrg   strcpy ((char *)&syms[0].sym.e.e_name[0], ".file");
    699  1.1  mrg   set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
    700  1.1  mrg   set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
    701  1.1  mrg   syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
    702  1.1  mrg   syms[0].sym.e_numaux[0] = 1;
    703  1.1  mrg   /* The name need not be nul-terminated if it fits into the x_fname field
    704  1.1  mrg      directly, but must be if it has to be placed into the string table.  */
    705  1.1  mrg   sflen = strlen (source_filename);
    706  1.1  mrg   if (sflen <= E_FILNMLEN)
    707  1.1  mrg     memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
    708  1.1  mrg   else
    709  1.1  mrg     {
    710  1.1  mrg       set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
    711  1.1  mrg       if (!simple_object_internal_write (descriptor, offset + name_offset,
    712  1.1  mrg 					 ((const unsigned char *)
    713  1.1  mrg 					  source_filename),
    714  1.1  mrg 					 sflen + 1, &errmsg, err))
    715  1.1  mrg 	return errmsg;
    716  1.1  mrg       name_offset += strlen (source_filename) + 1;
    717  1.1  mrg     }
    718  1.1  mrg   if (!simple_object_internal_write (descriptor, symtab_offset,
    719  1.1  mrg 				     (const unsigned char *) &syms[0],
    720  1.1  mrg 				     sizeof (syms), &errmsg, err))
    721  1.1  mrg     return errmsg;
    722  1.1  mrg 
    723  1.1  mrg   /* Write the string table length, followed by the strings and section
    724  1.1  mrg      symbols in step with each other.  */
    725  1.1  mrg   set_32 (strsizebuf, name_offset);
    726  1.1  mrg   if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
    727  1.1  mrg 				     &errmsg, err))
    728  1.1  mrg     return errmsg;
    729  1.1  mrg 
    730  1.1  mrg   name_offset = 4;
    731  1.1  mrg   secsym_offset = symtab_offset + sizeof (syms);
    732  1.1  mrg   memset (&syms[0], 0, sizeof (syms));
    733  1.1  mrg   set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
    734  1.1  mrg   syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
    735  1.1  mrg   syms[0].sym.e_numaux[0] = 1;
    736  1.1  mrg   secnum = 1;
    737  1.1  mrg 
    738  1.1  mrg   for (section = sobj->sections; section != NULL; section = section->next)
    739  1.1  mrg     {
    740  1.1  mrg       size_t namelen;
    741  1.1  mrg       size_t scnsize;
    742  1.1  mrg       struct simple_object_write_section_buffer *buffer;
    743  1.1  mrg 
    744  1.1  mrg       namelen = strlen (section->name);
    745  1.1  mrg       set_16 (&syms[0].sym.e_scnum[0], secnum++);
    746  1.1  mrg       scnsize = 0;
    747  1.1  mrg       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
    748  1.1  mrg 	scnsize += buffer->size;
    749  1.1  mrg       set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
    750  1.1  mrg       if (namelen > SCNNMLEN)
    751  1.1  mrg 	{
    752  1.1  mrg 	  set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
    753  1.1  mrg 	  set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
    754  1.1  mrg 	  if (!simple_object_internal_write (descriptor, offset + name_offset,
    755  1.1  mrg 					     ((const unsigned char *)
    756  1.1  mrg 					      section->name),
    757  1.1  mrg 					     namelen + 1, &errmsg, err))
    758  1.1  mrg 	    return errmsg;
    759  1.1  mrg 	  name_offset += namelen + 1;
    760  1.1  mrg 	}
    761  1.1  mrg       else
    762  1.1  mrg 	{
    763  1.1  mrg 	  memcpy (&syms[0].sym.e.e_name[0], section->name,
    764  1.1  mrg 		  strlen (section->name));
    765  1.1  mrg 	  memset (&syms[0].sym.e.e_name[strlen (section->name)], 0,
    766  1.1  mrg 		  E_SYMNMLEN - strlen (section->name));
    767  1.1  mrg 	}
    768  1.1  mrg 
    769  1.1  mrg       if (!simple_object_internal_write (descriptor, secsym_offset,
    770  1.1  mrg 					 (const unsigned char *) &syms[0],
    771  1.1  mrg 					 sizeof (syms), &errmsg, err))
    772  1.1  mrg 	return errmsg;
    773  1.1  mrg       secsym_offset += sizeof (syms);
    774  1.1  mrg     }
    775  1.1  mrg 
    776  1.1  mrg   if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns,
    777  1.1  mrg 					 symtab_offset, nsyms, &errmsg, err))
    778  1.1  mrg     return errmsg;
    779  1.1  mrg 
    780  1.1  mrg   return NULL;
    781  1.1  mrg }
    782  1.1  mrg 
    783  1.1  mrg /* Release the private data for an simple_object_write structure.  */
    784  1.1  mrg 
    785  1.1  mrg static void
    786  1.1  mrg simple_object_coff_release_write (void *data)
    787  1.1  mrg {
    788  1.1  mrg   XDELETE (data);
    789  1.1  mrg }
    790  1.1  mrg 
    791  1.1  mrg /* The COFF functions.  */
    792  1.1  mrg 
    793  1.1  mrg const struct simple_object_functions simple_object_coff_functions =
    794  1.1  mrg {
    795  1.1  mrg   simple_object_coff_match,
    796  1.1  mrg   simple_object_coff_find_sections,
    797  1.1  mrg   simple_object_coff_fetch_attributes,
    798  1.1  mrg   simple_object_coff_release_read,
    799  1.1  mrg   simple_object_coff_attributes_merge,
    800  1.1  mrg   simple_object_coff_release_attributes,
    801  1.1  mrg   simple_object_coff_start_write,
    802  1.1  mrg   simple_object_coff_write_to_file,
    803  1.6  mrg   simple_object_coff_release_write,
    804  1.6  mrg   NULL
    805  1.1  mrg };
    806