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