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