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