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