OSDN Git Service

2010-11-14 Kai Tietz <kai.tietz@onevision.com>
[pf3gnuchains/gcc-fork.git] / libiberty / simple-object-coff.c
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
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 51 Franklin Street - Fifth Floor,
18 Boston, 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
49 struct 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
68 struct 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
102 struct 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
128 union 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
165 struct 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
185 struct 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
201 struct 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
217 static 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
227 static void *
228 simple_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
300 static char *
301 simple_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
333 static const char *
334 simple_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
433 static void *
434 simple_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
451 static void
452 simple_object_coff_release_read (void *data)
453 {
454   XDELETE (data);
455 }
456
457 /* Compare two attributes structures.  */
458
459 static const char *
460 simple_object_coff_attributes_compare (void *data1, void *data2, int *err)
461 {
462   struct simple_object_coff_attributes *attrs1 =
463     (struct simple_object_coff_attributes *) data1;
464   struct simple_object_coff_attributes *attrs2 =
465     (struct simple_object_coff_attributes *) data2;
466
467   if (attrs1->magic != attrs2->magic
468       || attrs1->is_big_endian != attrs2->is_big_endian)
469     {
470       *err = 0;
471       return "COFF object format mismatch";
472     }
473   return NULL;
474 }
475
476 /* Release the private data for an attributes structure.  */
477
478 static void
479 simple_object_coff_release_attributes (void *data)
480 {
481   XDELETE (data);
482 }
483
484 /* Prepare to write out a file.  */
485
486 static void *
487 simple_object_coff_start_write (void *attributes_data,
488                                 const char **errmsg ATTRIBUTE_UNUSED,
489                                 int *err ATTRIBUTE_UNUSED)
490 {
491   struct simple_object_coff_attributes *attrs =
492     (struct simple_object_coff_attributes *) attributes_data;
493   struct simple_object_coff_attributes *ret;
494
495   /* We're just going to record the attributes, but we need to make a
496      copy because the user may delete them.  */
497   ret = XNEW (struct simple_object_coff_attributes);
498   *ret = *attrs;
499   return ret;
500 }
501
502 /* Write out a COFF filehdr.  */
503
504 static int
505 simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor,
506                                   unsigned int nscns, size_t symtab_offset,
507                                   unsigned int nsyms, const char **errmsg,
508                                   int *err)
509 {
510   struct simple_object_coff_attributes *attrs =
511     (struct simple_object_coff_attributes *) sobj->data;
512   unsigned char hdrbuf[sizeof (struct external_filehdr)];
513   unsigned char *hdr;
514   void (*set_16) (unsigned char *, unsigned short);
515   void (*set_32) (unsigned char *, unsigned int);
516
517   hdr = &hdrbuf[0];
518
519   set_16 = (attrs->is_big_endian
520             ? simple_object_set_big_16
521             : simple_object_set_little_16);
522   set_32 = (attrs->is_big_endian
523             ? simple_object_set_big_32
524             : simple_object_set_little_32);
525
526   memset (hdr, 0, sizeof (struct external_filehdr));
527
528   set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
529   set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
530   /* f_timdat left as zero.  */
531   set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
532   set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
533   /* f_opthdr left as zero.  */
534   set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
535
536   return simple_object_internal_write (descriptor, 0, hdrbuf,
537                                        sizeof (struct external_filehdr),
538                                        errmsg, err);
539 }
540
541 /* Write out a COFF section header.  */
542
543 static int
544 simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor,
545                                  const char *name, size_t *name_offset,
546                                  off_t scnhdr_offset, size_t scnsize,
547                                  off_t offset, unsigned int align,
548                                  const char **errmsg, int *err)
549 {
550   struct simple_object_coff_attributes *attrs =
551     (struct simple_object_coff_attributes *) sobj->data;
552   void (*set_32) (unsigned char *, unsigned int);
553   unsigned char hdrbuf[sizeof (struct external_scnhdr)];
554   unsigned char *hdr;
555   size_t namelen;
556   unsigned int flags;
557
558   set_32 = (attrs->is_big_endian
559             ? simple_object_set_big_32
560             : simple_object_set_little_32);
561
562   memset (hdrbuf, 0, sizeof hdrbuf);
563   hdr = &hdrbuf[0];
564
565   namelen = strlen (name);
566   if (namelen <= SCNNMLEN)
567     strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
568              SCNNMLEN);
569   else
570     {
571       snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
572                 SCNNMLEN, "/%lu", (unsigned long) *name_offset);
573       *name_offset += namelen + 1;
574     }
575
576   /* s_paddr left as zero.  */
577   /* s_vaddr left as zero.  */
578   set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
579   set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
580   /* s_relptr left as zero.  */
581   /* s_lnnoptr left as zero.  */
582   /* s_nreloc left as zero.  */
583   /* s_nlnno left as zero.  */
584   flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
585            | IMAGE_SCN_MEM_READ);
586   /* PE can represent alignment up to 13.  */
587   if (align > 13)
588     align = 13;
589   flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
590   set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);
591
592   return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
593                                        sizeof (struct external_scnhdr),
594                                        errmsg, err);
595 }
596
597 /* Write out a complete COFF file.  */
598
599 static const char *
600 simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor,
601                                   int *err)
602 {
603   struct simple_object_coff_attributes *attrs =
604     (struct simple_object_coff_attributes *) sobj->data;
605   unsigned int nscns, secnum;
606   simple_object_write_section *section;
607   off_t scnhdr_offset;
608   size_t symtab_offset;
609   off_t secsym_offset;
610   unsigned int nsyms;
611   size_t offset;
612   size_t name_offset;
613   const char *errmsg;
614   unsigned char strsizebuf[4];
615   /* The interface doesn't give us access to the name of the input file
616      yet.  We want to use its basename for the FILE symbol.  This is
617      what 'gas' uses when told to assemble from stdin.  */
618   const char *source_filename = "fake";
619   size_t sflen;
620   union
621   {
622     struct external_syment sym;
623     union external_auxent aux;
624   } syms[2];
625   void (*set_16) (unsigned char *, unsigned short);
626   void (*set_32) (unsigned char *, unsigned int);
627
628   set_16 = (attrs->is_big_endian
629             ? simple_object_set_big_16
630             : simple_object_set_little_16);
631   set_32 = (attrs->is_big_endian
632             ? simple_object_set_big_32
633             : simple_object_set_little_32);
634
635   nscns = 0;
636   for (section = sobj->sections; section != NULL; section = section->next)
637     ++nscns;
638
639   scnhdr_offset = sizeof (struct external_filehdr);
640   offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
641   name_offset = 4;
642   for (section = sobj->sections; section != NULL; section = section->next)
643     {
644       size_t mask;
645       size_t new_offset;
646       size_t scnsize;
647       struct simple_object_write_section_buffer *buffer;
648
649       mask = (1U << section->align) - 1;
650       new_offset = offset & mask;
651       new_offset &= ~ mask;
652       while (new_offset > offset)
653         {
654           unsigned char zeroes[16];
655           size_t write;
656
657           memset (zeroes, 0, sizeof zeroes);
658           write = new_offset - offset;
659           if (write > sizeof zeroes)
660             write = sizeof zeroes;
661           if (!simple_object_internal_write (descriptor, offset, zeroes, write,
662                                              &errmsg, err))
663             return errmsg;
664         }
665
666       scnsize = 0;
667       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
668         {
669           if (!simple_object_internal_write (descriptor, offset + scnsize,
670                                              ((const unsigned char *)
671                                               buffer->buffer),
672                                              buffer->size, &errmsg, err))
673             return errmsg;
674           scnsize += buffer->size;
675         }
676
677       if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name,
678                                             &name_offset, scnhdr_offset,
679                                             scnsize, offset, section->align,
680                                             &errmsg, err))
681         return errmsg;
682
683       scnhdr_offset += sizeof (struct external_scnhdr);
684       offset += scnsize;
685     }
686
687   /* Symbol table is always half-word aligned.  */
688   offset += (offset & 1);
689   /* There is a file symbol and a section symbol per section,
690      and each of these has a single auxiliary symbol following.  */
691   nsyms = 2 * (nscns + 1);
692   symtab_offset = offset;
693   /* Advance across space reserved for symbol table to locate
694      start of string table.  */
695   offset += nsyms * sizeof (struct external_syment);
696
697   /* Write out file symbol.  */
698   memset (&syms[0], 0, sizeof (syms));
699   strcpy ((char *)&syms[0].sym.e.e_name[0], ".file");
700   set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
701   set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
702   syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
703   syms[0].sym.e_numaux[0] = 1;
704   /* The name need not be nul-terminated if it fits into the x_fname field
705      directly, but must be if it has to be placed into the string table.  */
706   sflen = strlen (source_filename);
707   if (sflen <= E_FILNMLEN)
708     memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
709   else
710     {
711       set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
712       if (!simple_object_internal_write (descriptor, offset + name_offset,
713                                          ((const unsigned char *)
714                                           source_filename),
715                                          sflen + 1, &errmsg, err))
716         return errmsg;
717       name_offset += strlen (source_filename) + 1;
718     }
719   if (!simple_object_internal_write (descriptor, symtab_offset,
720                                      (const unsigned char *) &syms[0],
721                                      sizeof (syms), &errmsg, err))
722     return errmsg;
723
724   /* Write the string table length, followed by the strings and section
725      symbols in step with each other.  */
726   set_32 (strsizebuf, name_offset);
727   if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
728                                      &errmsg, err))
729     return errmsg;
730
731   name_offset = 4;
732   secsym_offset = symtab_offset + sizeof (syms);
733   memset (&syms[0], 0, sizeof (syms));
734   set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
735   syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
736   syms[0].sym.e_numaux[0] = 1;
737   secnum = 1;
738
739   for (section = sobj->sections; section != NULL; section = section->next)
740     {
741       size_t namelen;
742       size_t scnsize;
743       struct simple_object_write_section_buffer *buffer;
744
745       namelen = strlen (section->name);
746       set_16 (&syms[0].sym.e_scnum[0], secnum++);
747       scnsize = 0;
748       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
749         scnsize += buffer->size;
750       set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
751       if (namelen > SCNNMLEN)
752         {
753           set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
754           set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
755           if (!simple_object_internal_write (descriptor, offset + name_offset,
756                                              ((const unsigned char *)
757                                               section->name),
758                                              namelen + 1, &errmsg, err))
759             return errmsg;
760           name_offset += namelen + 1;
761         }
762       else
763         {
764           memcpy (&syms[0].sym.e.e_name[0], section->name,
765                   strlen (section->name));
766           memset (&syms[0].sym.e.e_name[strlen (section->name)], 0,
767                   E_SYMNMLEN - strlen (section->name));
768         }
769
770       if (!simple_object_internal_write (descriptor, secsym_offset,
771                                          (const unsigned char *) &syms[0],
772                                          sizeof (syms), &errmsg, err))
773         return errmsg;
774       secsym_offset += sizeof (syms);
775     }
776
777   if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns,
778                                          symtab_offset, nsyms, &errmsg, err))
779     return errmsg;
780
781   return NULL;
782 }
783
784 /* Release the private data for an simple_object_write structure.  */
785
786 static void
787 simple_object_coff_release_write (void *data)
788 {
789   XDELETE (data);
790 }
791
792 /* The COFF functions.  */
793
794 const struct simple_object_functions simple_object_coff_functions =
795 {
796   simple_object_coff_match,
797   simple_object_coff_find_sections,
798   simple_object_coff_fetch_attributes,
799   simple_object_coff_release_read,
800   simple_object_coff_attributes_compare,
801   simple_object_coff_release_attributes,
802   simple_object_coff_start_write,
803   simple_object_coff_write_to_file,
804   simple_object_coff_release_write
805 };