Home | History | Annotate | Download | only in libiberty
      1 /* simple-object-coff.c -- routines to manipulate XCOFF object files.
      2    Copyright 2013 Free Software Foundation, Inc.
      3    Written by Ian Lance Taylor, Google and David Edelsohn, IBM.
      4 
      5 This program is free software; you can redistribute it and/or modify it
      6 under the terms of the GNU General Public License as published by the
      7 Free Software Foundation; either version 2, or (at your option) any
      8 later version.
      9 
     10 This program is distributed in the hope that it will be useful,
     11 but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, 51 Franklin Street - Fifth Floor,
     18 Boston, MA 02110-1301, USA.  */
     19 
     20 #include "config.h"
     21 #include "libiberty.h"
     22 #include "simple-object.h"
     23 
     24 #include <errno.h>
     25 #include <stddef.h>
     26 
     27 #ifdef HAVE_STDLIB_H
     28 #include <stdlib.h>
     29 #endif
     30 
     31 #ifdef HAVE_STDINT_H
     32 #include <stdint.h>
     33 #endif
     34 
     35 #ifdef HAVE_STRING_H
     36 #include <string.h>
     37 #endif
     38 
     39 #ifdef HAVE_INTTYPES_H
     40 #include <inttypes.h>
     41 #endif
     42 
     43 #include "simple-object-common.h"
     44 
     45 /* XCOFF structures and constants.  */
     46 
     47 /* XCOFF file header.  */
     48 
     49 struct external_filehdr
     50 {
     51   unsigned char f_magic[2];	/* magic number			*/
     52   unsigned char f_nscns[2];	/* number of sections		*/
     53   unsigned char f_timdat[4];	/* time & date stamp		*/
     54   union
     55   {
     56     struct
     57     {
     58       unsigned char f_symptr[4];	/* file pointer to symtab	*/
     59       unsigned char f_nsyms[4];	/* number of symtab entries	*/
     60       unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
     61       unsigned char f_flags[2];	/* flags			*/
     62     } xcoff32;
     63     struct
     64     {
     65       unsigned char f_symptr[8];	/* file pointer to symtab	*/
     66       unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
     67       unsigned char f_flags[2];	/* flags			*/
     68       unsigned char f_nsyms[4];	/* number of symtab entries	*/
     69     } xcoff64;
     70   } u;
     71 };
     72 
     73 /* Bits for filehdr f_flags field.  */
     74 
     75 #define F_EXEC			(0x0002)
     76 
     77 /* The known values of f_magic in an XCOFF file header.  */
     78 
     79 #define U802WRMAGIC 0730        /* Writeable text segments.  */
     80 #define U802ROMAGIC 0735        /* Readonly sharable text segments.  */
     81 #define U802TOCMAGIC 0737       /* Readonly text segments and TOC.  */
     82 #define U803XTOCMAGIC 0757      /* Aix 4.3 64-bit XCOFF.  */
     83 #define U64_TOCMAGIC 0767       /* AIX 5+ 64-bit XCOFF.  */
     84 
     85 /* XCOFF section header.  */
     86 
     87 struct external_scnhdr
     88 {
     89   unsigned char s_name[8];	/* section name				*/
     90   union
     91   {
     92     struct
     93     {
     94       unsigned char s_paddr[4];	/* physical address, aliased s_nlib 	*/
     95       unsigned char s_vaddr[4];	/* virtual address			*/
     96       unsigned char s_size[4];	/* section size				*/
     97       unsigned char s_scnptr[4];	/* file ptr to raw data for section */
     98       unsigned char s_relptr[4];	/* file ptr to relocation	*/
     99       unsigned char s_lnnoptr[4];	/* file ptr to line numbers	*/
    100       unsigned char s_nreloc[2];	/* number of relocation entries	*/
    101       unsigned char s_nlnno[2];	/* number of line number entries	*/
    102       unsigned char s_flags[4];	/* flags				*/
    103     } xcoff32;
    104     struct
    105     {
    106       unsigned char s_paddr[8];	/* physical address, aliased s_nlib 	*/
    107       unsigned char s_vaddr[8];	/* virtual address			*/
    108       unsigned char s_size[8];	/* section size				*/
    109       unsigned char s_scnptr[8];	/* file ptr to raw data for section */
    110       unsigned char s_relptr[8];	/* file ptr to relocation	*/
    111       unsigned char s_lnnoptr[8];	/* file ptr to line numbers	*/
    112       unsigned char s_nreloc[4];	/* number of relocation entries	*/
    113       unsigned char s_nlnno[4];	/* number of line number entries	*/
    114       unsigned char s_flags[4];	/* flags				*/
    115     } xcoff64;
    116   } u;
    117 };
    118 
    119 #define SCNHSZ32	(40)
    120 #define SCNHSZ64	(68)
    121 
    122 /* The length of the s_name field in struct external_scnhdr.  */
    123 
    124 #define SCNNMLEN	(8)
    125 
    126 /* Bits for scnhdr s_flags field.  */
    127 
    128 #define STYP_DATA			0x40
    129 
    130 /* XCOFF symbol table entry.  */
    131 
    132 
    133 #define N_SYMNMLEN	(8)	/* # characters in a symbol name	*/
    134 
    135 /* The format of an XCOFF symbol-table entry.  */
    136 struct external_syment
    137 {
    138   union {
    139     struct {
    140       union {
    141         /* The name of the symbol.  There is an implicit null character
    142            after the end of the array.  */
    143         char n_name[N_SYMNMLEN];
    144         struct {
    145           /* If n_zeroes is zero, n_offset is the offset the name from
    146              the start of the string table.  */
    147           unsigned char n_zeroes[4];
    148           unsigned char n_offset[4];
    149         } n;
    150       } n;
    151 
    152       /* The symbol's value.  */
    153       unsigned char n_value[4];
    154     } xcoff32;
    155     struct {
    156       /* The symbol's value.  */
    157       unsigned char n_value[8];
    158 
    159       /* The offset of the symbol from the start of the string table.  */
    160       unsigned char n_offset[4];
    161     } xcoff64;
    162   } u;
    163 
    164   /* The number of the section to which this symbol belongs.  */
    165   unsigned char n_scnum[2];
    166 
    167   /* The type of symbol.  (It can be interpreted as an n_lang
    168      and an n_cpu byte, but we don't care about that here.)  */
    169   unsigned char n_type[2];
    170 
    171   /* The class of symbol (a C_* value).  */
    172   unsigned char n_sclass[1];
    173 
    174   /* The number of auxiliary symbols attached to this entry.  */
    175   unsigned char n_numaux[1];
    176 };
    177 
    178 #define SYMESZ		(18)
    179 
    180 /* Length allowed for filename in aux sym format 4.  */
    181 
    182 #define FILNMLEN	(14)
    183 
    184 /* Omits x_sym and other unused variants.  */
    185 
    186 union external_auxent
    187 {
    188   /* Aux sym format 4: file.  */
    189   union
    190   {
    191     char x_fname[FILNMLEN];
    192     struct
    193     {
    194       unsigned char x_zeroes[4];
    195       unsigned char x_offset[4];
    196       unsigned char x_pad[FILNMLEN-8];
    197       unsigned char x_ftype;
    198     } _x;
    199   } x_file;
    200   /* Aux sym format 5: section.  */
    201   struct
    202   {
    203     unsigned char x_scnlen[4];		/* section length		*/
    204     unsigned char x_nreloc[2];		/* # relocation entries		*/
    205     unsigned char x_nlinno[2];		/* # line numbers		*/
    206   } x_scn;
    207   /* CSECT auxiliary entry.  */
    208   union
    209   {
    210     struct
    211     {
    212       struct
    213       {
    214 	unsigned char x_scnlen[4];	/* csect length */
    215 	unsigned char x_parmhash[4];	/* parm type hash index */
    216 	unsigned char x_snhash[2];	/* sect num with parm hash */
    217 	unsigned char x_smtyp;		/* symbol align and type */
    218 	unsigned char x_smclas;		/* storage mapping class */
    219 	unsigned char x_stab;		/* dbx stab info index */
    220 	unsigned char x_snstab[2];	/* sect num with dbx stab */
    221       } x_csect;
    222     } xcoff32;
    223     struct
    224     {
    225       struct
    226       {
    227 	unsigned char x_scnlen_lo[4];	/* csect length */
    228 	unsigned char x_parmhash[4];	/* parm type hash index */
    229 	unsigned char x_snhash[2];	/* sect num with parm hash */
    230 	unsigned char x_smtyp;		/* symbol align and type */
    231 	unsigned char x_smclas;		/* storage mapping class */
    232 	unsigned char x_scnlen_hi[4];
    233 	unsigned char pad;
    234 	unsigned char x_auxtype;
    235       } x_csect;
    236     } xcoff64;
    237   } u;
    238   /* SECTION/DWARF auxiliary entry.  */
    239   struct
    240   {
    241     unsigned char x_scnlen[4];		/* section length */
    242     unsigned char pad1[4];
    243     unsigned char x_nreloc[4];		/* number RLDs */
    244   } x_sect;
    245 };
    246 
    247 /* Symbol-related constants.  */
    248 
    249 #define N_DEBUG		(-2)
    250 #define IMAGE_SYM_TYPE_NULL	(0)
    251 #define IMAGE_SYM_DTYPE_NULL	(0)
    252 #define IMAGE_SYM_CLASS_STATIC	(3)
    253 #define IMAGE_SYM_CLASS_FILE	(103)
    254 
    255 #define IMAGE_SYM_TYPE \
    256   ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
    257 
    258 #define C_STAT		(3)
    259 #define C_FILE		(103)
    260 
    261 /* Private data for an simple_object_read.  */
    262 
    263 struct simple_object_xcoff_read
    264 {
    265   /* Magic number.  */
    266   unsigned short magic;
    267   /* Number of sections.  */
    268   unsigned short nscns;
    269   /* File offset of symbol table.  */
    270   off_t symptr;
    271   /* Number of symbol table entries.  */
    272   unsigned int nsyms;
    273   /* Flags.  */
    274   unsigned short flags;
    275   /* Offset of section headers in file.  */
    276   off_t scnhdr_offset;
    277 };
    278 
    279 /* Private data for an simple_object_attributes.  */
    280 
    281 struct simple_object_xcoff_attributes
    282 {
    283   /* Magic number.  */
    284   unsigned short magic;
    285   /* Flags.  */
    286   unsigned short flags;
    287 };
    288 
    289 /* See if we have a XCOFF file.  */
    290 
    291 static void *
    292 simple_object_xcoff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
    293 			   int descriptor, off_t offset,
    294 			   const char *segment_name ATTRIBUTE_UNUSED,
    295 			   const char **errmsg, int *err)
    296 {
    297   unsigned short magic;
    298   unsigned short (*fetch_16) (const unsigned char *);
    299   unsigned int (*fetch_32) (const unsigned char *);
    300   ulong_type (*fetch_64) (const unsigned char *);
    301   unsigned char hdrbuf[sizeof (struct external_filehdr)];
    302   struct simple_object_xcoff_read *ocr;
    303   int u64;
    304 
    305   magic = simple_object_fetch_big_16 (header);
    306 
    307   if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC)
    308     {
    309       *errmsg = NULL;
    310       *err = 0;
    311       return NULL;
    312     }
    313 
    314   fetch_16 = simple_object_fetch_big_16;
    315   fetch_32 = simple_object_fetch_big_32;
    316   fetch_64 = simple_object_fetch_big_64;
    317 
    318   if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
    319 				    errmsg, err))
    320     return NULL;
    321 
    322   u64 = magic == U64_TOCMAGIC;
    323 
    324   ocr = XNEW (struct simple_object_xcoff_read);
    325   ocr->magic = magic;
    326   ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
    327   if (u64)
    328     {
    329       ocr->symptr = fetch_64 (hdrbuf
    330 			      + offsetof (struct external_filehdr,
    331 					  u.xcoff64.f_symptr));
    332       ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
    333 						u.xcoff64.f_nsyms));
    334       ocr->scnhdr_offset = (sizeof (struct external_filehdr)
    335 			    + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
    336 							   u.xcoff64.f_opthdr)));
    337 
    338     }
    339   else
    340     {
    341       ocr->symptr = fetch_32 (hdrbuf
    342 			      + offsetof (struct external_filehdr,
    343 					  u.xcoff32.f_symptr));
    344       ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
    345 						u.xcoff32.f_nsyms));
    346       ocr->scnhdr_offset = (sizeof (struct external_filehdr) - 4
    347 			    + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
    348 							   u.xcoff32.f_opthdr)));
    349 
    350     }
    351 
    352   return (void *) ocr;
    353 }
    354 
    355 /* Read the string table in a XCOFF file.  */
    356 
    357 static char *
    358 simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
    359 				 const char **errmsg, int *err)
    360 {
    361   struct simple_object_xcoff_read *ocr =
    362     (struct simple_object_xcoff_read *) sobj->data;
    363   off_t strtab_offset;
    364   unsigned char strsizebuf[4];
    365   size_t strsize;
    366   char *strtab;
    367 
    368   strtab_offset = sobj->offset + ocr->symptr
    369     + ocr->nsyms * SYMESZ;
    370   if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
    371 				    strsizebuf, 4, errmsg, err))
    372     return NULL;
    373   strsize = simple_object_fetch_big_32 (strsizebuf);
    374   strtab = XNEWVEC (char, strsize);
    375   if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
    376 				    (unsigned char *) strtab, strsize, errmsg,
    377 				    err))
    378     {
    379       XDELETEVEC (strtab);
    380       return NULL;
    381     }
    382   *strtab_size = strsize;
    383   return strtab;
    384 }
    385 
    386 /* Find all sections in a XCOFF file.  */
    387 
    388 static const char *
    389 simple_object_xcoff_find_sections (simple_object_read *sobj,
    390 				  int (*pfn) (void *, const char *,
    391 					      off_t offset, off_t length),
    392 				  void *data,
    393 				  int *err)
    394 {
    395   struct simple_object_xcoff_read *ocr =
    396     (struct simple_object_xcoff_read *) sobj->data;
    397   int u64 = ocr->magic == U64_TOCMAGIC;
    398   size_t scnhdr_size;
    399   unsigned char *scnbuf;
    400   const char *errmsg;
    401   unsigned int (*fetch_32) (const unsigned char *);
    402   ulong_type (*fetch_64) (const unsigned char *);
    403   unsigned int nscns;
    404   char *strtab;
    405   size_t strtab_size;
    406   unsigned int i;
    407 
    408   scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32;
    409   scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
    410   if (!simple_object_internal_read (sobj->descriptor,
    411 				    sobj->offset + ocr->scnhdr_offset,
    412 				    scnbuf, scnhdr_size * ocr->nscns, &errmsg,
    413 				    err))
    414     {
    415       XDELETEVEC (scnbuf);
    416       return errmsg;
    417     }
    418 
    419   fetch_32 = simple_object_fetch_big_32;
    420   fetch_64 = simple_object_fetch_big_64;
    421 
    422   nscns = ocr->nscns;
    423   strtab = NULL;
    424   strtab_size = 0;
    425   for (i = 0; i < nscns; ++i)
    426     {
    427       unsigned char *scnhdr;
    428       unsigned char *scnname;
    429       char namebuf[SCNNMLEN + 1];
    430       char *name;
    431       off_t scnptr;
    432       unsigned int size;
    433 
    434       scnhdr = scnbuf + i * scnhdr_size;
    435       scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
    436       memcpy (namebuf, scnname, SCNNMLEN);
    437       namebuf[SCNNMLEN] = '\0';
    438       name = &namebuf[0];
    439       if (namebuf[0] == '/')
    440 	{
    441 	  size_t strindex;
    442 	  char *end;
    443 
    444 	  strindex = strtol (namebuf + 1, &end, 10);
    445 	  if (*end == '\0')
    446 	    {
    447 	      /* The real section name is found in the string
    448 		 table.  */
    449 	      if (strtab == NULL)
    450 		{
    451 		  strtab = simple_object_xcoff_read_strtab (sobj,
    452 							   &strtab_size,
    453 							   &errmsg, err);
    454 		  if (strtab == NULL)
    455 		    {
    456 		      XDELETEVEC (scnbuf);
    457 		      return errmsg;
    458 		    }
    459 		}
    460 
    461 	      if (strindex < 4 || strindex >= strtab_size)
    462 		{
    463 		  XDELETEVEC (strtab);
    464 		  XDELETEVEC (scnbuf);
    465 		  *err = 0;
    466 		  return "section string index out of range";
    467 		}
    468 
    469 	      name = strtab + strindex;
    470 	    }
    471 	}
    472 
    473       if (u64)
    474 	{
    475 	  scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
    476 						u.xcoff64.s_scnptr));
    477 	  size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
    478 					      u.xcoff64.s_size));
    479 	}
    480       else
    481 	{
    482 	  scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
    483 						u.xcoff32.s_scnptr));
    484 	  size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
    485 					      u.xcoff32.s_size));
    486 	}
    487 
    488       if (!(*pfn) (data, name, scnptr, size))
    489 	break;
    490     }
    491 
    492   if (strtab != NULL)
    493     XDELETEVEC (strtab);
    494   XDELETEVEC (scnbuf);
    495 
    496   return NULL;
    497 }
    498 
    499 /* Fetch the attributes for an simple_object_read.  */
    500 
    501 static void *
    502 simple_object_xcoff_fetch_attributes (simple_object_read *sobj,
    503 				     const char **errmsg ATTRIBUTE_UNUSED,
    504 				     int *err ATTRIBUTE_UNUSED)
    505 {
    506   struct simple_object_xcoff_read *ocr =
    507     (struct simple_object_xcoff_read *) sobj->data;
    508   struct simple_object_xcoff_attributes *ret;
    509 
    510   ret = XNEW (struct simple_object_xcoff_attributes);
    511   ret->magic = ocr->magic;
    512   ret->flags = ocr->flags;
    513   return ret;
    514 }
    515 
    516 /* Release the private data for an simple_object_read.  */
    517 
    518 static void
    519 simple_object_xcoff_release_read (void *data)
    520 {
    521   XDELETE (data);
    522 }
    523 
    524 /* Compare two attributes structures.  */
    525 
    526 static const char *
    527 simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err)
    528 {
    529   struct simple_object_xcoff_attributes *to =
    530     (struct simple_object_xcoff_attributes *) todata;
    531   struct simple_object_xcoff_attributes *from =
    532     (struct simple_object_xcoff_attributes *) fromdata;
    533 
    534   if (to->magic != from->magic)
    535     {
    536       *err = 0;
    537       return "XCOFF object format mismatch";
    538     }
    539   return NULL;
    540 }
    541 
    542 /* Release the private data for an attributes structure.  */
    543 
    544 static void
    545 simple_object_xcoff_release_attributes (void *data)
    546 {
    547   XDELETE (data);
    548 }
    549 
    550 /* Prepare to write out a file.  */
    551 
    552 static void *
    553 simple_object_xcoff_start_write (void *attributes_data,
    554 				const char **errmsg ATTRIBUTE_UNUSED,
    555 				int *err ATTRIBUTE_UNUSED)
    556 {
    557   struct simple_object_xcoff_attributes *attrs =
    558     (struct simple_object_xcoff_attributes *) attributes_data;
    559   struct simple_object_xcoff_attributes *ret;
    560 
    561   /* We're just going to record the attributes, but we need to make a
    562      copy because the user may delete them.  */
    563   ret = XNEW (struct simple_object_xcoff_attributes);
    564   *ret = *attrs;
    565   return ret;
    566 }
    567 
    568 /* Write out a XCOFF filehdr.  */
    569 
    570 static int
    571 simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor,
    572 				  unsigned int nscns, size_t symtab_offset,
    573 				  unsigned int nsyms, const char **errmsg,
    574 				  int *err)
    575 {
    576   struct simple_object_xcoff_attributes *attrs =
    577     (struct simple_object_xcoff_attributes *) sobj->data;
    578   int u64 = attrs->magic == U64_TOCMAGIC;
    579   unsigned char hdrbuf[sizeof (struct external_filehdr)];
    580   unsigned char *hdr;
    581   void (*set_16) (unsigned char *, unsigned short);
    582   void (*set_32) (unsigned char *, unsigned int);
    583   void (*set_64) (unsigned char *, ulong_type);
    584 
    585   hdr = &hdrbuf[0];
    586 
    587   set_16 = simple_object_set_big_16;
    588   set_32 = simple_object_set_big_32;
    589   set_64 = simple_object_set_big_64;
    590 
    591   memset (hdr, 0, sizeof (struct external_filehdr));
    592 
    593   set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
    594   set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
    595   /* f_timdat left as zero.  */
    596   if (u64)
    597     {
    598       set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
    599 	      symtab_offset);
    600       set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
    601 	      nsyms);
    602       /* f_opthdr left as zero.  */
    603       set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
    604 	      attrs->flags);
    605     }
    606   else
    607     {
    608       set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
    609 	      symtab_offset);
    610       set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
    611 	      nsyms);
    612       /* f_opthdr left as zero.  */
    613       set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
    614 	      attrs->flags);
    615     }
    616 
    617   return simple_object_internal_write (descriptor, 0, hdrbuf,
    618 				       sizeof (struct external_filehdr),
    619 				       errmsg, err);
    620 }
    621 
    622 /* Write out a XCOFF section header.  */
    623 
    624 static int
    625 simple_object_xcoff_write_scnhdr (simple_object_write *sobj,
    626 				  int descriptor,
    627 				  const char *name, size_t *name_offset,
    628 				  off_t scnhdr_offset, size_t scnsize,
    629 				  off_t offset, unsigned int align,
    630 				  const char **errmsg, int *err)
    631 {
    632   struct simple_object_xcoff_read *ocr =
    633     (struct simple_object_xcoff_read *) sobj->data;
    634   int u64 = ocr->magic == U64_TOCMAGIC;
    635   void (*set_32) (unsigned char *, unsigned int);
    636   void (*set_64) (unsigned char *, unsigned int);
    637   unsigned char hdrbuf[sizeof (struct external_scnhdr)];
    638   unsigned char *hdr;
    639   size_t namelen;
    640   unsigned int flags;
    641 
    642   set_32 = simple_object_set_big_32;
    643   set_64 = simple_object_set_big_32;
    644 
    645   memset (hdrbuf, 0, sizeof hdrbuf);
    646   hdr = &hdrbuf[0];
    647 
    648   namelen = strlen (name);
    649   if (namelen <= SCNNMLEN)
    650     strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name),
    651 	     name, SCNNMLEN);
    652   else
    653     {
    654       snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
    655 		SCNNMLEN, "/%lu", (unsigned long) *name_offset);
    656       *name_offset += namelen + 1;
    657     }
    658 
    659   /* s_paddr left as zero.  */
    660   /* s_vaddr left as zero.  */
    661   if (u64)
    662     {
    663       set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size),
    664 	      scnsize);
    665       set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr),
    666 	      offset);
    667     }
    668   else
    669     {
    670       set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size),
    671 	      scnsize);
    672       set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr),
    673 	      offset);
    674     }
    675   /* s_relptr left as zero.  */
    676   /* s_lnnoptr left as zero.  */
    677   /* s_nreloc left as zero.  */
    678   /* s_nlnno left as zero.  */
    679   flags = STYP_DATA;
    680   if (align > 13)
    681     align = 13;
    682   if (u64)
    683     set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags);
    684   else
    685     set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags);
    686 
    687   return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
    688 				       u64 ? SCNHSZ64 : SCNHSZ32,
    689 				       errmsg, err);
    690 }
    691 
    692 /* Write out a complete XCOFF file.  */
    693 
    694 static const char *
    695 simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor,
    696 				  int *err)
    697 {
    698   struct simple_object_xcoff_read *ocr =
    699     (struct simple_object_xcoff_read *) sobj->data;
    700   int u64 = ocr->magic == U64_TOCMAGIC;
    701   unsigned int nscns, secnum;
    702   simple_object_write_section *section;
    703   off_t scnhdr_offset;
    704   size_t symtab_offset;
    705   off_t secsym_offset;
    706   unsigned int nsyms;
    707   size_t offset;
    708   size_t name_offset;
    709   const char *errmsg;
    710   unsigned char strsizebuf[4];
    711   /* The interface doesn't give us access to the name of the input file
    712      yet.  We want to use its basename for the FILE symbol.  This is
    713      what 'gas' uses when told to assemble from stdin.  */
    714   const char *source_filename = "fake";
    715   size_t sflen;
    716   union
    717   {
    718     struct external_syment sym;
    719     union external_auxent aux;
    720   } syms[2];
    721   void (*set_16) (unsigned char *, unsigned short);
    722   void (*set_32) (unsigned char *, unsigned int);
    723 
    724   set_16 = simple_object_set_big_16;
    725   set_32 = simple_object_set_big_32;
    726 
    727   nscns = 0;
    728   for (section = sobj->sections; section != NULL; section = section->next)
    729     ++nscns;
    730 
    731   scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0);
    732   offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32);
    733   name_offset = 4;
    734   for (section = sobj->sections; section != NULL; section = section->next)
    735     {
    736       size_t mask;
    737       size_t new_offset;
    738       size_t scnsize;
    739       struct simple_object_write_section_buffer *buffer;
    740 
    741       mask = (1U << section->align) - 1;
    742       new_offset = offset & mask;
    743       new_offset &= ~ mask;
    744       while (new_offset > offset)
    745 	{
    746 	  unsigned char zeroes[16];
    747 	  size_t write;
    748 
    749 	  memset (zeroes, 0, sizeof zeroes);
    750 	  write = new_offset - offset;
    751 	  if (write > sizeof zeroes)
    752 	    write = sizeof zeroes;
    753 	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
    754 					     &errmsg, err))
    755 	    return errmsg;
    756 	}
    757 
    758       scnsize = 0;
    759       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
    760 	{
    761 	  if (!simple_object_internal_write (descriptor, offset + scnsize,
    762 					     ((const unsigned char *)
    763 					      buffer->buffer),
    764 					     buffer->size, &errmsg, err))
    765 	    return errmsg;
    766 	  scnsize += buffer->size;
    767 	}
    768 
    769       if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name,
    770 					    &name_offset, scnhdr_offset,
    771 					    scnsize, offset, section->align,
    772 					    &errmsg, err))
    773 	return errmsg;
    774 
    775       scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32;
    776       offset += scnsize;
    777     }
    778 
    779   /* Symbol table is always half-word aligned.  */
    780   offset += (offset & 1);
    781   /* There is a file symbol and a section symbol per section,
    782      and each of these has a single auxiliary symbol following.  */
    783   nsyms = 2 * (nscns + 1);
    784   symtab_offset = offset;
    785   /* Advance across space reserved for symbol table to locate
    786      start of string table.  */
    787   offset += nsyms * SYMESZ;
    788 
    789   /* Write out file symbol.  */
    790   memset (&syms[0], 0, sizeof (syms));
    791   if (!u64)
    792     strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file");
    793   set_16 (&syms[0].sym.n_scnum[0], N_DEBUG);
    794   set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
    795   syms[0].sym.n_sclass[0] = C_FILE;
    796   syms[0].sym.n_numaux[0] = 1;
    797   /* The name need not be nul-terminated if it fits into the x_fname field
    798      directly, but must be if it has to be placed into the string table.  */
    799   sflen = strlen (source_filename);
    800   if (sflen <= FILNMLEN)
    801     memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
    802   else
    803     {
    804       set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset);
    805       if (!simple_object_internal_write (descriptor, offset + name_offset,
    806 					 ((const unsigned char *)
    807 					  source_filename),
    808 					 sflen + 1, &errmsg, err))
    809 	return errmsg;
    810       name_offset += strlen (source_filename) + 1;
    811     }
    812   if (!simple_object_internal_write (descriptor, symtab_offset,
    813 				     (const unsigned char *) &syms[0],
    814 				     sizeof (syms), &errmsg, err))
    815     return errmsg;
    816 
    817   /* Write the string table length, followed by the strings and section
    818      symbols in step with each other.  */
    819   set_32 (strsizebuf, name_offset);
    820   if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
    821 				     &errmsg, err))
    822     return errmsg;
    823 
    824   name_offset = 4;
    825   secsym_offset = symtab_offset + sizeof (syms);
    826   memset (&syms[0], 0, sizeof (syms));
    827   set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
    828   syms[0].sym.n_sclass[0] = C_STAT;
    829   syms[0].sym.n_numaux[0] = 1;
    830   secnum = 1;
    831 
    832   for (section = sobj->sections; section != NULL; section = section->next)
    833     {
    834       size_t namelen;
    835       size_t scnsize;
    836       struct simple_object_write_section_buffer *buffer;
    837 
    838       namelen = strlen (section->name);
    839       set_16 (&syms[0].sym.n_scnum[0], secnum++);
    840       scnsize = 0;
    841       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
    842 	scnsize += buffer->size;
    843       set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
    844       if (namelen > SCNNMLEN)
    845 	{
    846 	  set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0);
    847 	  set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset);
    848 	  if (!simple_object_internal_write (descriptor, offset + name_offset,
    849 					     ((const unsigned char *)
    850 					      section->name),
    851 					     namelen + 1, &errmsg, err))
    852 	    return errmsg;
    853 	  name_offset += namelen + 1;
    854 	}
    855       else
    856 	{
    857 	  memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name,
    858 		  strlen (section->name));
    859 	  memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0,
    860 		  N_SYMNMLEN - strlen (section->name));
    861 	}
    862 
    863       if (!simple_object_internal_write (descriptor, secsym_offset,
    864 					 (const unsigned char *) &syms[0],
    865 					 sizeof (syms), &errmsg, err))
    866 	return errmsg;
    867       secsym_offset += sizeof (syms);
    868     }
    869 
    870   if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns,
    871 					 symtab_offset, nsyms, &errmsg, err))
    872     return errmsg;
    873 
    874   return NULL;
    875 }
    876 
    877 /* Release the private data for an simple_object_write structure.  */
    878 
    879 static void
    880 simple_object_xcoff_release_write (void *data)
    881 {
    882   XDELETE (data);
    883 }
    884 
    885 /* The XCOFF functions.  */
    886 
    887 const struct simple_object_functions simple_object_xcoff_functions =
    888 {
    889   simple_object_xcoff_match,
    890   simple_object_xcoff_find_sections,
    891   simple_object_xcoff_fetch_attributes,
    892   simple_object_xcoff_release_read,
    893   simple_object_xcoff_attributes_merge,
    894   simple_object_xcoff_release_attributes,
    895   simple_object_xcoff_start_write,
    896   simple_object_xcoff_write_to_file,
    897   simple_object_xcoff_release_write
    898 };
    899