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