1/* simple-object-coff.c -- routines to manipulate COFF object files.
2 Copyright (C) 2010-2025 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 { .magic: 0x14c, .is_big_endian: 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
221 /* x86_64. */
222 { .magic: 0x8664, .is_big_endian: 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
223 /* AArch64. */
224 { .magic: 0xaa64, .is_big_endian: 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
225};
226
227/* See if we have a COFF file. */
228
229static void *
230simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
231 int descriptor, off_t offset,
232 const char *segment_name ATTRIBUTE_UNUSED,
233 const char **errmsg, int *err)
234{
235 size_t c;
236 unsigned short magic_big;
237 unsigned short magic_little;
238 unsigned short magic;
239 size_t i;
240 int is_big_endian;
241 unsigned short (*fetch_16) (const unsigned char *);
242 unsigned int (*fetch_32) (const unsigned char *);
243 unsigned char hdrbuf[sizeof (struct external_filehdr)];
244 unsigned short flags;
245 struct simple_object_coff_read *ocr;
246
247 c = sizeof (coff_magic) / sizeof (coff_magic[0]);
248 magic_big = simple_object_fetch_big_16 (buf: header);
249 magic_little = simple_object_fetch_little_16 (buf: header);
250 for (i = 0; i < c; ++i)
251 {
252 if (coff_magic[i].is_big_endian
253 ? coff_magic[i].magic == magic_big
254 : coff_magic[i].magic == magic_little)
255 break;
256 }
257 if (i >= c)
258 {
259 *errmsg = NULL;
260 *err = 0;
261 return NULL;
262 }
263 is_big_endian = coff_magic[i].is_big_endian;
264
265 magic = is_big_endian ? magic_big : magic_little;
266 fetch_16 = (is_big_endian
267 ? simple_object_fetch_big_16
268 : simple_object_fetch_little_16);
269 fetch_32 = (is_big_endian
270 ? simple_object_fetch_big_32
271 : simple_object_fetch_little_32);
272
273 if (!simple_object_internal_read (descriptor, offset, buffer: hdrbuf, size: sizeof hdrbuf,
274 errmsg, err))
275 return NULL;
276
277 flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
278 if ((flags & coff_magic[i].non_object_flags) != 0)
279 {
280 *errmsg = "not relocatable object file";
281 *err = 0;
282 return NULL;
283 }
284
285 ocr = XNEW (struct simple_object_coff_read);
286 ocr->magic = magic;
287 ocr->is_big_endian = is_big_endian;
288 ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
289 ocr->symptr = fetch_32 (hdrbuf
290 + offsetof (struct external_filehdr, f_symptr));
291 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
292 ocr->flags = flags;
293 ocr->scnhdr_offset = (sizeof (struct external_filehdr)
294 + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
295 f_opthdr)));
296
297 return (void *) ocr;
298}
299
300/* Read the string table in a COFF file. */
301
302static char *
303simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
304 const char **errmsg, int *err)
305{
306 struct simple_object_coff_read *ocr =
307 (struct simple_object_coff_read *) sobj->data;
308 off_t strtab_offset;
309 unsigned char strsizebuf[4];
310 size_t strsize;
311 char *strtab;
312
313 strtab_offset = sobj->offset + ocr->symptr
314 + ocr->nsyms * sizeof (struct external_syment);
315 if (!simple_object_internal_read (descriptor: sobj->descriptor, offset: strtab_offset,
316 buffer: strsizebuf, size: 4, errmsg, err))
317 return NULL;
318 strsize = (ocr->is_big_endian
319 ? simple_object_fetch_big_32 (buf: strsizebuf)
320 : simple_object_fetch_little_32 (buf: strsizebuf));
321 strtab = XNEWVEC (char, strsize);
322 if (!simple_object_internal_read (descriptor: sobj->descriptor, offset: strtab_offset,
323 buffer: (unsigned char *) strtab, size: strsize, errmsg,
324 err))
325 {
326 XDELETEVEC (strtab);
327 return NULL;
328 }
329 *strtab_size = strsize;
330 return strtab;
331}
332
333/* Find all sections in a COFF file. */
334
335static const char *
336simple_object_coff_find_sections (simple_object_read *sobj,
337 int (*pfn) (void *, const char *,
338 off_t offset, off_t length),
339 void *data,
340 int *err)
341{
342 struct simple_object_coff_read *ocr =
343 (struct simple_object_coff_read *) sobj->data;
344 size_t scnhdr_size;
345 unsigned char *scnbuf;
346 const char *errmsg;
347 unsigned int (*fetch_32) (const unsigned char *);
348 unsigned int nscns;
349 char *strtab;
350 size_t strtab_size;
351 unsigned int i;
352
353 scnhdr_size = sizeof (struct external_scnhdr);
354 scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
355 if (!simple_object_internal_read (descriptor: sobj->descriptor,
356 offset: sobj->offset + ocr->scnhdr_offset,
357 buffer: scnbuf, size: scnhdr_size * ocr->nscns, errmsg: &errmsg,
358 err))
359 {
360 XDELETEVEC (scnbuf);
361 return errmsg;
362 }
363
364 fetch_32 = (ocr->is_big_endian
365 ? simple_object_fetch_big_32
366 : simple_object_fetch_little_32);
367
368 nscns = ocr->nscns;
369 strtab = NULL;
370 strtab_size = 0;
371 for (i = 0; i < nscns; ++i)
372 {
373 unsigned char *scnhdr;
374 unsigned char *scnname;
375 char namebuf[SCNNMLEN + 1];
376 char *name;
377 off_t scnptr;
378 unsigned int size;
379
380 scnhdr = scnbuf + i * scnhdr_size;
381 scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
382 memcpy (dest: namebuf, src: scnname, SCNNMLEN);
383 namebuf[SCNNMLEN] = '\0';
384 name = &namebuf[0];
385 if (namebuf[0] == '/')
386 {
387 size_t strindex;
388 char *end;
389
390 strindex = strtol (nptr: namebuf + 1, endptr: &end, base: 10);
391 if (*end == '\0')
392 {
393 /* The real section name is found in the string
394 table. */
395 if (strtab == NULL)
396 {
397 strtab = simple_object_coff_read_strtab (sobj,
398 strtab_size: &strtab_size,
399 errmsg: &errmsg, err);
400 if (strtab == NULL)
401 {
402 XDELETEVEC (scnbuf);
403 return errmsg;
404 }
405 }
406
407 if (strindex < 4 || strindex >= strtab_size)
408 {
409 XDELETEVEC (strtab);
410 XDELETEVEC (scnbuf);
411 *err = 0;
412 return "section string index out of range";
413 }
414
415 name = strtab + strindex;
416 }
417 }
418
419 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
420 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));
421
422 if (!(*pfn) (data, name, scnptr, size))
423 break;
424 }
425
426 if (strtab != NULL)
427 XDELETEVEC (strtab);
428 XDELETEVEC (scnbuf);
429
430 return NULL;
431}
432
433/* Fetch the attributes for an simple_object_read. */
434
435static void *
436simple_object_coff_fetch_attributes (simple_object_read *sobj,
437 const char **errmsg ATTRIBUTE_UNUSED,
438 int *err ATTRIBUTE_UNUSED)
439{
440 struct simple_object_coff_read *ocr =
441 (struct simple_object_coff_read *) sobj->data;
442 struct simple_object_coff_attributes *ret;
443
444 ret = XNEW (struct simple_object_coff_attributes);
445 ret->magic = ocr->magic;
446 ret->is_big_endian = ocr->is_big_endian;
447 ret->flags = ocr->flags;
448 return ret;
449}
450
451/* Release the private data for an simple_object_read. */
452
453static void
454simple_object_coff_release_read (void *data)
455{
456 XDELETE (data);
457}
458
459/* Compare two attributes structures. */
460
461static const char *
462simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err)
463{
464 struct simple_object_coff_attributes *to =
465 (struct simple_object_coff_attributes *) todata;
466 struct simple_object_coff_attributes *from =
467 (struct simple_object_coff_attributes *) fromdata;
468
469 if (to->magic != from->magic || to->is_big_endian != from->is_big_endian)
470 {
471 *err = 0;
472 return "COFF object format mismatch";
473 }
474 return NULL;
475}
476
477/* Release the private data for an attributes structure. */
478
479static void
480simple_object_coff_release_attributes (void *data)
481{
482 XDELETE (data);
483}
484
485/* Prepare to write out a file. */
486
487static void *
488simple_object_coff_start_write (void *attributes_data,
489 const char **errmsg ATTRIBUTE_UNUSED,
490 int *err ATTRIBUTE_UNUSED)
491{
492 struct simple_object_coff_attributes *attrs =
493 (struct simple_object_coff_attributes *) attributes_data;
494 struct simple_object_coff_attributes *ret;
495
496 /* We're just going to record the attributes, but we need to make a
497 copy because the user may delete them. */
498 ret = XNEW (struct simple_object_coff_attributes);
499 *ret = *attrs;
500 return ret;
501}
502
503/* Write out a COFF filehdr. */
504
505static int
506simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor,
507 unsigned int nscns, size_t symtab_offset,
508 unsigned int nsyms, const char **errmsg,
509 int *err)
510{
511 struct simple_object_coff_attributes *attrs =
512 (struct simple_object_coff_attributes *) sobj->data;
513 unsigned char hdrbuf[sizeof (struct external_filehdr)];
514 unsigned char *hdr;
515 void (*set_16) (unsigned char *, unsigned short);
516 void (*set_32) (unsigned char *, unsigned int);
517
518 hdr = &hdrbuf[0];
519
520 set_16 = (attrs->is_big_endian
521 ? simple_object_set_big_16
522 : simple_object_set_little_16);
523 set_32 = (attrs->is_big_endian
524 ? simple_object_set_big_32
525 : simple_object_set_little_32);
526
527 memset (s: hdr, c: 0, n: sizeof (struct external_filehdr));
528
529 set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
530 set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
531 /* f_timdat left as zero. */
532 set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
533 set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
534 /* f_opthdr left as zero. */
535 set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
536
537 return simple_object_internal_write (descriptor, offset: 0, buffer: hdrbuf,
538 size: sizeof (struct external_filehdr),
539 errmsg, err);
540}
541
542/* Write out a COFF section header. */
543
544static int
545simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor,
546 const char *name, size_t *name_offset,
547 off_t scnhdr_offset, size_t scnsize,
548 off_t offset, unsigned int align,
549 const char **errmsg, int *err)
550{
551 struct simple_object_coff_attributes *attrs =
552 (struct simple_object_coff_attributes *) sobj->data;
553 void (*set_32) (unsigned char *, unsigned int);
554 unsigned char hdrbuf[sizeof (struct external_scnhdr)];
555 unsigned char *hdr;
556 size_t namelen;
557 unsigned int flags;
558
559 set_32 = (attrs->is_big_endian
560 ? simple_object_set_big_32
561 : simple_object_set_little_32);
562
563 memset (s: hdrbuf, c: 0, n: sizeof hdrbuf);
564 hdr = &hdrbuf[0];
565
566 namelen = strlen (s: name);
567 if (namelen <= SCNNMLEN)
568 strncpy (dest: (char *) hdr + offsetof (struct external_scnhdr, s_name), src: name,
569 SCNNMLEN);
570 else
571 {
572 snprintf (s: (char *) hdr + offsetof (struct external_scnhdr, s_name),
573 SCNNMLEN, format: "/%lu", (unsigned long) *name_offset);
574 *name_offset += namelen + 1;
575 }
576
577 /* s_paddr left as zero. */
578 /* s_vaddr left as zero. */
579 set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
580 set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
581 /* s_relptr left as zero. */
582 /* s_lnnoptr left as zero. */
583 /* s_nreloc left as zero. */
584 /* s_nlnno left as zero. */
585 flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
586 | IMAGE_SCN_MEM_READ);
587 /* PE can represent alignment up to 13. */
588 if (align > 13)
589 align = 13;
590 flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
591 set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);
592
593 return simple_object_internal_write (descriptor, offset: scnhdr_offset, buffer: hdrbuf,
594 size: sizeof (struct external_scnhdr),
595 errmsg, err);
596}
597
598/* Write out a complete COFF file. */
599
600static const char *
601simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor,
602 int *err)
603{
604 struct simple_object_coff_attributes *attrs =
605 (struct simple_object_coff_attributes *) sobj->data;
606 unsigned int nscns, secnum;
607 simple_object_write_section *section;
608 off_t scnhdr_offset;
609 size_t symtab_offset;
610 off_t secsym_offset;
611 unsigned int nsyms;
612 size_t offset;
613 size_t name_offset;
614 const char *errmsg;
615 unsigned char strsizebuf[4];
616 /* The interface doesn't give us access to the name of the input file
617 yet. We want to use its basename for the FILE symbol. This is
618 what 'gas' uses when told to assemble from stdin. */
619 const char *source_filename = "fake";
620 size_t sflen;
621 union
622 {
623 struct external_syment sym;
624 union external_auxent aux;
625 } syms[2];
626 void (*set_16) (unsigned char *, unsigned short);
627 void (*set_32) (unsigned char *, unsigned int);
628
629 set_16 = (attrs->is_big_endian
630 ? simple_object_set_big_16
631 : simple_object_set_little_16);
632 set_32 = (attrs->is_big_endian
633 ? simple_object_set_big_32
634 : simple_object_set_little_32);
635
636 nscns = 0;
637 for (section = sobj->sections; section != NULL; section = section->next)
638 ++nscns;
639
640 scnhdr_offset = sizeof (struct external_filehdr);
641 offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
642 name_offset = 4;
643 for (section = sobj->sections; section != NULL; section = section->next)
644 {
645 size_t mask;
646 size_t new_offset;
647 size_t scnsize;
648 struct simple_object_write_section_buffer *buffer;
649
650 mask = (1U << section->align) - 1;
651 new_offset = offset & mask;
652 new_offset &= ~ mask;
653 while (new_offset > offset)
654 {
655 unsigned char zeroes[16];
656 size_t write;
657
658 memset (s: zeroes, c: 0, n: sizeof zeroes);
659 write = new_offset - offset;
660 if (write > sizeof zeroes)
661 write = sizeof zeroes;
662 if (!simple_object_internal_write (descriptor, offset, buffer: zeroes, size: write,
663 errmsg: &errmsg, err))
664 return errmsg;
665 }
666
667 scnsize = 0;
668 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
669 {
670 if (!simple_object_internal_write (descriptor, offset: offset + scnsize,
671 buffer: ((const unsigned char *)
672 buffer->buffer),
673 size: buffer->size, errmsg: &errmsg, err))
674 return errmsg;
675 scnsize += buffer->size;
676 }
677
678 if (!simple_object_coff_write_scnhdr (sobj, descriptor, name: section->name,
679 name_offset: &name_offset, scnhdr_offset,
680 scnsize, offset, align: section->align,
681 errmsg: &errmsg, err))
682 return errmsg;
683
684 scnhdr_offset += sizeof (struct external_scnhdr);
685 offset += scnsize;
686 }
687
688 /* Symbol table is always half-word aligned. */
689 offset += (offset & 1);
690 /* There is a file symbol and a section symbol per section,
691 and each of these has a single auxiliary symbol following. */
692 nsyms = 2 * (nscns + 1);
693 symtab_offset = offset;
694 /* Advance across space reserved for symbol table to locate
695 start of string table. */
696 offset += nsyms * sizeof (struct external_syment);
697
698 /* Write out file symbol. */
699 memset (s: &syms[0], c: 0, n: sizeof (syms));
700 strcpy (dest: (char *)&syms[0].sym.e.e_name[0], src: ".file");
701 set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
702 set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
703 syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
704 syms[0].sym.e_numaux[0] = 1;
705 /* The name need not be nul-terminated if it fits into the x_fname field
706 directly, but must be if it has to be placed into the string table. */
707 sflen = strlen (s: source_filename);
708 if (sflen <= E_FILNMLEN)
709 memcpy (dest: &syms[1].aux.x_file.x_fname[0], src: source_filename, n: sflen);
710 else
711 {
712 set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
713 if (!simple_object_internal_write (descriptor, offset: offset + name_offset,
714 buffer: ((const unsigned char *)
715 source_filename),
716 size: sflen + 1, errmsg: &errmsg, err))
717 return errmsg;
718 name_offset += strlen (s: source_filename) + 1;
719 }
720 if (!simple_object_internal_write (descriptor, offset: symtab_offset,
721 buffer: (const unsigned char *) &syms[0],
722 size: sizeof (syms), errmsg: &errmsg, err))
723 return errmsg;
724
725 /* Write the string table length, followed by the strings and section
726 symbols in step with each other. */
727 set_32 (strsizebuf, name_offset);
728 if (!simple_object_internal_write (descriptor, offset, buffer: strsizebuf, size: 4,
729 errmsg: &errmsg, err))
730 return errmsg;
731
732 name_offset = 4;
733 secsym_offset = symtab_offset + sizeof (syms);
734 memset (s: &syms[0], c: 0, n: sizeof (syms));
735 set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
736 syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
737 syms[0].sym.e_numaux[0] = 1;
738 secnum = 1;
739
740 for (section = sobj->sections; section != NULL; section = section->next)
741 {
742 size_t namelen;
743 size_t scnsize;
744 struct simple_object_write_section_buffer *buffer;
745
746 namelen = strlen (s: section->name);
747 set_16 (&syms[0].sym.e_scnum[0], secnum++);
748 scnsize = 0;
749 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
750 scnsize += buffer->size;
751 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
752 if (namelen > SCNNMLEN)
753 {
754 set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
755 set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
756 if (!simple_object_internal_write (descriptor, offset: offset + name_offset,
757 buffer: ((const unsigned char *)
758 section->name),
759 size: namelen + 1, errmsg: &errmsg, err))
760 return errmsg;
761 name_offset += namelen + 1;
762 }
763 else
764 {
765 memcpy (dest: &syms[0].sym.e.e_name[0], src: section->name,
766 n: strlen (s: section->name));
767 memset (s: &syms[0].sym.e.e_name[strlen (s: section->name)], c: 0,
768 E_SYMNMLEN - strlen (s: section->name));
769 }
770
771 if (!simple_object_internal_write (descriptor, offset: secsym_offset,
772 buffer: (const unsigned char *) &syms[0],
773 size: sizeof (syms), errmsg: &errmsg, err))
774 return errmsg;
775 secsym_offset += sizeof (syms);
776 }
777
778 if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns,
779 symtab_offset, nsyms, errmsg: &errmsg, err))
780 return errmsg;
781
782 return NULL;
783}
784
785/* Release the private data for an simple_object_write structure. */
786
787static void
788simple_object_coff_release_write (void *data)
789{
790 XDELETE (data);
791}
792
793/* The COFF functions. */
794
795const struct simple_object_functions simple_object_coff_functions =
796{
797 .match: simple_object_coff_match,
798 .find_sections: simple_object_coff_find_sections,
799 .fetch_attributes: simple_object_coff_fetch_attributes,
800 .release_read: simple_object_coff_release_read,
801 .attributes_merge: simple_object_coff_attributes_merge,
802 .release_attributes: simple_object_coff_release_attributes,
803 .start_write: simple_object_coff_start_write,
804 .write_to_file: simple_object_coff_write_to_file,
805 .release_write: simple_object_coff_release_write,
806 NULL
807};
808

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of libiberty/simple-object-coff.c