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