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