[gcc]
[official-gcc.git] / libiberty / simple-object-xcoff.c
blob9a8f581563f0e9c83828c3ec1742e4773c37a2a0
1 /* simple-object-coff.c -- routines to manipulate XCOFF object files.
2 Copyright (C) 2013-2017 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google and David Edelsohn, IBM.
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.
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.
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. */
20 #include "config.h"
21 #include "libiberty.h"
22 #include "simple-object.h"
24 #include <errno.h>
25 #include <stddef.h>
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
31 #ifdef HAVE_STDINT_H
32 #include <stdint.h>
33 #endif
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
39 #ifdef HAVE_INTTYPES_H
40 #include <inttypes.h>
41 #endif
43 #include "simple-object-common.h"
45 /* XCOFF structures and constants. */
47 /* XCOFF file header. */
49 struct external_filehdr
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 union
56 struct
58 unsigned char f_symptr[4]; /* file pointer to symtab */
59 unsigned char f_nsyms[4]; /* number of symtab entries */
60 unsigned char f_opthdr[2]; /* sizeof(optional hdr) */
61 unsigned char f_flags[2]; /* flags */
62 } xcoff32;
63 struct
65 unsigned char f_symptr[8]; /* file pointer to symtab */
66 unsigned char f_opthdr[2]; /* sizeof(optional hdr) */
67 unsigned char f_flags[2]; /* flags */
68 unsigned char f_nsyms[4]; /* number of symtab entries */
69 } xcoff64;
70 } u;
73 /* Bits for filehdr f_flags field. */
75 #define F_EXEC (0x0002)
77 /* The known values of f_magic in an XCOFF file header. */
79 #define U802WRMAGIC 0730 /* Writeable text segments. */
80 #define U802ROMAGIC 0735 /* Readonly sharable text segments. */
81 #define U802TOCMAGIC 0737 /* Readonly text segments and TOC. */
82 #define U803XTOCMAGIC 0757 /* Aix 4.3 64-bit XCOFF. */
83 #define U64_TOCMAGIC 0767 /* AIX 5+ 64-bit XCOFF. */
85 /* XCOFF section header. */
87 struct external_scnhdr
89 unsigned char s_name[8]; /* section name */
90 union
92 struct
94 unsigned char s_paddr[4]; /* physical address, aliased s_nlib */
95 unsigned char s_vaddr[4]; /* virtual address */
96 unsigned char s_size[4]; /* section size */
97 unsigned char s_scnptr[4]; /* file ptr to raw data for section */
98 unsigned char s_relptr[4]; /* file ptr to relocation */
99 unsigned char s_lnnoptr[4]; /* file ptr to line numbers */
100 unsigned char s_nreloc[2]; /* number of relocation entries */
101 unsigned char s_nlnno[2]; /* number of line number entries */
102 unsigned char s_flags[4]; /* flags */
103 } xcoff32;
104 struct
106 unsigned char s_paddr[8]; /* physical address, aliased s_nlib */
107 unsigned char s_vaddr[8]; /* virtual address */
108 unsigned char s_size[8]; /* section size */
109 unsigned char s_scnptr[8]; /* file ptr to raw data for section */
110 unsigned char s_relptr[8]; /* file ptr to relocation */
111 unsigned char s_lnnoptr[8]; /* file ptr to line numbers */
112 unsigned char s_nreloc[4]; /* number of relocation entries */
113 unsigned char s_nlnno[4]; /* number of line number entries */
114 unsigned char s_flags[4]; /* flags */
115 } xcoff64;
116 } u;
119 #define SCNHSZ32 (40)
120 #define SCNHSZ64 (68)
122 /* The length of the s_name field in struct external_scnhdr. */
124 #define SCNNMLEN (8)
126 /* Bits for scnhdr s_flags field. */
128 #define STYP_DATA 0x40
130 /* XCOFF symbol table entry. */
133 #define N_SYMNMLEN (8) /* # characters in a symbol name */
135 /* The format of an XCOFF symbol-table entry. */
136 struct external_syment
138 union {
139 struct {
140 union {
141 /* The name of the symbol. There is an implicit null character
142 after the end of the array. */
143 char n_name[N_SYMNMLEN];
144 struct {
145 /* If n_zeroes is zero, n_offset is the offset the name from
146 the start of the string table. */
147 unsigned char n_zeroes[4];
148 unsigned char n_offset[4];
149 } n;
150 } n;
152 /* The symbol's value. */
153 unsigned char n_value[4];
154 } xcoff32;
155 struct {
156 /* The symbol's value. */
157 unsigned char n_value[8];
159 /* The offset of the symbol from the start of the string table. */
160 unsigned char n_offset[4];
161 } xcoff64;
162 } u;
164 /* The number of the section to which this symbol belongs. */
165 unsigned char n_scnum[2];
167 /* The type of symbol. (It can be interpreted as an n_lang
168 and an n_cpu byte, but we don't care about that here.) */
169 unsigned char n_type[2];
171 /* The class of symbol (a C_* value). */
172 unsigned char n_sclass[1];
174 /* The number of auxiliary symbols attached to this entry. */
175 unsigned char n_numaux[1];
178 #define SYMESZ (18)
180 /* Length allowed for filename in aux sym format 4. */
182 #define FILNMLEN (14)
184 /* Omits x_sym and other unused variants. */
186 union external_auxent
188 /* Aux sym format 4: file. */
189 union
191 char x_fname[FILNMLEN];
192 struct
194 unsigned char x_zeroes[4];
195 unsigned char x_offset[4];
196 unsigned char x_pad[FILNMLEN-8];
197 unsigned char x_ftype;
198 } _x;
199 } x_file;
200 /* Aux sym format 5: section. */
201 struct
203 unsigned char x_scnlen[4]; /* section length */
204 unsigned char x_nreloc[2]; /* # relocation entries */
205 unsigned char x_nlinno[2]; /* # line numbers */
206 } x_scn;
207 /* CSECT auxiliary entry. */
208 union
210 struct
212 struct
214 unsigned char x_scnlen[4]; /* csect length */
215 unsigned char x_parmhash[4]; /* parm type hash index */
216 unsigned char x_snhash[2]; /* sect num with parm hash */
217 unsigned char x_smtyp; /* symbol align and type */
218 unsigned char x_smclas; /* storage mapping class */
219 unsigned char x_stab; /* dbx stab info index */
220 unsigned char x_snstab[2]; /* sect num with dbx stab */
221 } x_csect;
222 } xcoff32;
223 struct
225 struct
227 unsigned char x_scnlen_lo[4]; /* csect length */
228 unsigned char x_parmhash[4]; /* parm type hash index */
229 unsigned char x_snhash[2]; /* sect num with parm hash */
230 unsigned char x_smtyp; /* symbol align and type */
231 unsigned char x_smclas; /* storage mapping class */
232 unsigned char x_scnlen_hi[4];
233 unsigned char pad;
234 unsigned char x_auxtype;
235 } x_csect;
236 } xcoff64;
237 } u;
238 /* SECTION/DWARF auxiliary entry. */
239 struct
241 unsigned char x_scnlen[4]; /* section length */
242 unsigned char pad1[4];
243 unsigned char x_nreloc[4]; /* number RLDs */
244 } x_sect;
247 /* Symbol-related constants. */
249 #define N_DEBUG (-2)
250 #define IMAGE_SYM_TYPE_NULL (0)
251 #define IMAGE_SYM_DTYPE_NULL (0)
252 #define IMAGE_SYM_CLASS_STATIC (3)
253 #define IMAGE_SYM_CLASS_FILE (103)
255 #define IMAGE_SYM_TYPE \
256 ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
258 #define C_EXT (2)
259 #define C_STAT (3)
260 #define C_FILE (103)
261 #define C_HIDEXT (107)
263 #define XTY_SD (1) /* section definition */
265 #define XMC_XO (7) /* extended operation */
267 /* Private data for an simple_object_read. */
269 struct simple_object_xcoff_read
271 /* Magic number. */
272 unsigned short magic;
273 /* Number of sections. */
274 unsigned short nscns;
275 /* File offset of symbol table. */
276 off_t symptr;
277 /* Number of symbol table entries. */
278 unsigned int nsyms;
279 /* Flags. */
280 unsigned short flags;
281 /* Offset of section headers in file. */
282 off_t scnhdr_offset;
285 /* Private data for an simple_object_attributes. */
287 struct simple_object_xcoff_attributes
289 /* Magic number. */
290 unsigned short magic;
291 /* Flags. */
292 unsigned short flags;
295 /* See if we have a XCOFF file. */
297 static void *
298 simple_object_xcoff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
299 int descriptor, off_t offset,
300 const char *segment_name ATTRIBUTE_UNUSED,
301 const char **errmsg, int *err)
303 unsigned short magic;
304 unsigned short (*fetch_16) (const unsigned char *);
305 unsigned int (*fetch_32) (const unsigned char *);
306 ulong_type (*fetch_64) (const unsigned char *);
307 unsigned char hdrbuf[sizeof (struct external_filehdr)];
308 struct simple_object_xcoff_read *ocr;
309 int u64;
311 magic = simple_object_fetch_big_16 (header);
313 if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC)
315 *errmsg = NULL;
316 *err = 0;
317 return NULL;
320 fetch_16 = simple_object_fetch_big_16;
321 fetch_32 = simple_object_fetch_big_32;
322 fetch_64 = simple_object_fetch_big_64;
324 if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
325 errmsg, err))
326 return NULL;
328 u64 = magic == U64_TOCMAGIC;
330 ocr = XNEW (struct simple_object_xcoff_read);
331 ocr->magic = magic;
332 ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
333 if (u64)
335 ocr->symptr = fetch_64 (hdrbuf
336 + offsetof (struct external_filehdr,
337 u.xcoff64.f_symptr));
338 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
339 u.xcoff64.f_nsyms));
340 ocr->scnhdr_offset = (sizeof (struct external_filehdr)
341 + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
342 u.xcoff64.f_opthdr)));
345 else
347 ocr->symptr = fetch_32 (hdrbuf
348 + offsetof (struct external_filehdr,
349 u.xcoff32.f_symptr));
350 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
351 u.xcoff32.f_nsyms));
352 ocr->scnhdr_offset = (sizeof (struct external_filehdr) - 4
353 + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
354 u.xcoff32.f_opthdr)));
358 return (void *) ocr;
361 /* Read the string table in a XCOFF file. */
363 static char *
364 simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
365 const char **errmsg, int *err)
367 struct simple_object_xcoff_read *ocr =
368 (struct simple_object_xcoff_read *) sobj->data;
369 off_t strtab_offset;
370 unsigned char strsizebuf[4];
371 size_t strsize;
372 char *strtab;
374 strtab_offset = sobj->offset + ocr->symptr
375 + ocr->nsyms * SYMESZ;
376 if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
377 strsizebuf, 4, errmsg, err))
378 return NULL;
379 strsize = simple_object_fetch_big_32 (strsizebuf);
380 strtab = XNEWVEC (char, strsize);
381 if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
382 (unsigned char *) strtab, strsize, errmsg,
383 err))
385 XDELETEVEC (strtab);
386 return NULL;
388 *strtab_size = strsize;
389 return strtab;
392 /* Find all sections in a XCOFF file. */
394 static const char *
395 simple_object_xcoff_find_sections (simple_object_read *sobj,
396 int (*pfn) (void *, const char *,
397 off_t offset, off_t length),
398 void *data,
399 int *err)
401 struct simple_object_xcoff_read *ocr =
402 (struct simple_object_xcoff_read *) sobj->data;
403 int u64 = ocr->magic == U64_TOCMAGIC;
404 size_t scnhdr_size;
405 unsigned char *scnbuf;
406 const char *errmsg;
407 unsigned short (*fetch_16) (const unsigned char *);
408 unsigned int (*fetch_32) (const unsigned char *);
409 ulong_type (*fetch_64) (const unsigned char *);
410 unsigned int nscns;
411 char *strtab;
412 size_t strtab_size;
413 struct external_syment *symtab = NULL;
414 unsigned int i;
416 scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32;
417 scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
418 if (!simple_object_internal_read (sobj->descriptor,
419 sobj->offset + ocr->scnhdr_offset,
420 scnbuf, scnhdr_size * ocr->nscns, &errmsg,
421 err))
423 XDELETEVEC (scnbuf);
424 return errmsg;
427 fetch_16 = simple_object_fetch_big_16;
428 fetch_32 = simple_object_fetch_big_32;
429 fetch_64 = simple_object_fetch_big_64;
431 nscns = ocr->nscns;
432 strtab = NULL;
433 strtab_size = 0;
434 for (i = 0; i < nscns; ++i)
436 unsigned char *scnhdr;
437 unsigned char *scnname;
438 char namebuf[SCNNMLEN + 1];
439 char *name;
440 off_t scnptr;
441 off_t size;
443 scnhdr = scnbuf + i * scnhdr_size;
444 scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
445 memcpy (namebuf, scnname, SCNNMLEN);
446 namebuf[SCNNMLEN] = '\0';
447 name = &namebuf[0];
448 if (namebuf[0] == '/')
450 size_t strindex;
451 char *end;
453 strindex = strtol (namebuf + 1, &end, 10);
454 if (*end == '\0')
456 /* The real section name is found in the string
457 table. */
458 if (strtab == NULL)
460 strtab = simple_object_xcoff_read_strtab (sobj,
461 &strtab_size,
462 &errmsg, err);
463 if (strtab == NULL)
465 XDELETEVEC (scnbuf);
466 return errmsg;
470 if (strindex < 4 || strindex >= strtab_size)
472 XDELETEVEC (strtab);
473 XDELETEVEC (scnbuf);
474 *err = 0;
475 return "section string index out of range";
478 name = strtab + strindex;
482 if (u64)
484 scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
485 u.xcoff64.s_scnptr));
486 size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
487 u.xcoff64.s_size));
489 else
491 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
492 u.xcoff32.s_scnptr));
493 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
494 u.xcoff32.s_size));
497 if (!(*pfn) (data, name, scnptr, size))
498 break;
501 /* Special handling for .go_export csect. */
502 if (ocr->nsyms > 0)
504 unsigned char *sym;
505 const char *n_name;
506 off_t size, n_value;
507 unsigned int n_numaux, n_offset, n_zeroes;
508 short n_scnum;
510 /* Read symbol table. */
511 symtab = XNEWVEC (struct external_syment, ocr->nsyms * SYMESZ);
512 if (!simple_object_internal_read (sobj->descriptor,
513 sobj->offset + ocr->symptr,
514 (unsigned char *) symtab,
515 ocr->nsyms * SYMESZ,
516 &errmsg, err))
518 XDELETEVEC (symtab);
519 XDELETEVEC (scnbuf);
520 return NULL;
523 /* Search in symbol table if we have a ".go_export" symbol. */
524 for (i = 0; i < ocr->nsyms; i += n_numaux + 1)
526 sym = (unsigned char *) &symtab[i];
527 n_numaux = symtab[i].n_numaux[0];
529 if (symtab[i].n_sclass[0] != C_EXT
530 && symtab[i].n_sclass[0] != C_HIDEXT)
531 continue;
533 /* Must have at least one csect auxiliary entry. */
534 if (n_numaux < 1 || i + n_numaux >= ocr->nsyms)
535 continue;
537 n_scnum = fetch_16 (sym + offsetof (struct external_syment,
538 n_scnum));
539 if (n_scnum < 1 || (unsigned int) n_scnum > nscns)
540 continue;
542 if (u64)
544 n_value = fetch_64 (sym + offsetof (struct external_syment,
545 u.xcoff64.n_value));
546 n_offset = fetch_32 (sym + offsetof (struct external_syment,
547 u.xcoff64.n_offset));
549 else
551 /* ".go_export" is longer than N_SYMNMLEN. */
552 n_zeroes = fetch_32 (sym + offsetof (struct external_syment,
553 u.xcoff32.n.n.n_zeroes));
554 if (n_zeroes != 0)
555 continue;
557 n_value = fetch_32 (sym + offsetof (struct external_syment,
558 u.xcoff32.n_value));
559 n_offset = fetch_32 (sym + offsetof (struct external_syment,
560 u.xcoff32.n.n.n_offset));
563 /* The real symbol name is found in the string table. */
564 if (strtab == NULL)
566 strtab = simple_object_xcoff_read_strtab (sobj,
567 &strtab_size,
568 &errmsg, err);
569 if (strtab == NULL)
571 XDELETEVEC (symtab);
572 XDELETEVEC (scnbuf);
573 return errmsg;
577 if (n_offset >= strtab_size)
579 XDELETEVEC (strtab);
580 XDELETEVEC (symtab);
581 XDELETEVEC (scnbuf);
582 *err = 0;
583 return "symbol string index out of range";
585 n_name = strtab + n_offset;
587 if (!strcmp (n_name, ".go_export"))
589 union external_auxent *auxent;
590 unsigned char *aux, *scnhdr;
591 off_t scnptr, x_scnlen;
593 /* Found .go_export symbol, read its csect auxiliary entry.
594 By convention, it is the last auxiliary entry. */
595 auxent = (union external_auxent *) &symtab[i + n_numaux];
596 aux = (unsigned char *) auxent;
597 if (u64)
599 if ((auxent->u.xcoff64.x_csect.x_smtyp & 0x7) != XTY_SD
600 || auxent->u.xcoff64.x_csect.x_smclas != XMC_XO)
601 continue;
603 x_scnlen = fetch_32 (aux + offsetof (union external_auxent,
604 u.xcoff64.x_csect.x_scnlen_hi));
605 x_scnlen = x_scnlen << 32
606 | fetch_32 (aux + offsetof (union external_auxent,
607 u.xcoff64.x_csect.x_scnlen_lo));
609 else
611 if ((auxent->u.xcoff32.x_csect.x_smtyp & 0x7) != XTY_SD
612 || auxent->u.xcoff32.x_csect.x_smclas != XMC_XO)
613 continue;
615 x_scnlen = fetch_32 (aux + offsetof (union external_auxent,
616 u.xcoff32.x_csect.x_scnlen));
619 /* Get header of containing section. */
620 scnhdr = scnbuf + (n_scnum - 1) * scnhdr_size;
621 if (u64)
623 scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
624 u.xcoff64.s_scnptr));
625 size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
626 u.xcoff64.s_size));
628 else
630 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
631 u.xcoff32.s_scnptr));
632 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
633 u.xcoff32.s_size));
635 if (n_value + x_scnlen > size)
636 break;
638 (*pfn) (data, ".go_export", scnptr + n_value, x_scnlen);
639 break;
644 if (symtab != NULL)
645 XDELETEVEC (symtab);
646 if (strtab != NULL)
647 XDELETEVEC (strtab);
648 XDELETEVEC (scnbuf);
650 return NULL;
653 /* Fetch the attributes for an simple_object_read. */
655 static void *
656 simple_object_xcoff_fetch_attributes (simple_object_read *sobj,
657 const char **errmsg ATTRIBUTE_UNUSED,
658 int *err ATTRIBUTE_UNUSED)
660 struct simple_object_xcoff_read *ocr =
661 (struct simple_object_xcoff_read *) sobj->data;
662 struct simple_object_xcoff_attributes *ret;
664 ret = XNEW (struct simple_object_xcoff_attributes);
665 ret->magic = ocr->magic;
666 ret->flags = ocr->flags;
667 return ret;
670 /* Release the private data for an simple_object_read. */
672 static void
673 simple_object_xcoff_release_read (void *data)
675 XDELETE (data);
678 /* Compare two attributes structures. */
680 static const char *
681 simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err)
683 struct simple_object_xcoff_attributes *to =
684 (struct simple_object_xcoff_attributes *) todata;
685 struct simple_object_xcoff_attributes *from =
686 (struct simple_object_xcoff_attributes *) fromdata;
688 if (to->magic != from->magic)
690 *err = 0;
691 return "XCOFF object format mismatch";
693 return NULL;
696 /* Release the private data for an attributes structure. */
698 static void
699 simple_object_xcoff_release_attributes (void *data)
701 XDELETE (data);
704 /* Prepare to write out a file. */
706 static void *
707 simple_object_xcoff_start_write (void *attributes_data,
708 const char **errmsg ATTRIBUTE_UNUSED,
709 int *err ATTRIBUTE_UNUSED)
711 struct simple_object_xcoff_attributes *attrs =
712 (struct simple_object_xcoff_attributes *) attributes_data;
713 struct simple_object_xcoff_attributes *ret;
715 /* We're just going to record the attributes, but we need to make a
716 copy because the user may delete them. */
717 ret = XNEW (struct simple_object_xcoff_attributes);
718 *ret = *attrs;
719 return ret;
722 /* Write out a XCOFF filehdr. */
724 static int
725 simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor,
726 unsigned int nscns, size_t symtab_offset,
727 unsigned int nsyms, const char **errmsg,
728 int *err)
730 struct simple_object_xcoff_attributes *attrs =
731 (struct simple_object_xcoff_attributes *) sobj->data;
732 int u64 = attrs->magic == U64_TOCMAGIC;
733 unsigned char hdrbuf[sizeof (struct external_filehdr)];
734 unsigned char *hdr;
735 void (*set_16) (unsigned char *, unsigned short);
736 void (*set_32) (unsigned char *, unsigned int);
737 void (*set_64) (unsigned char *, ulong_type);
739 hdr = &hdrbuf[0];
741 set_16 = simple_object_set_big_16;
742 set_32 = simple_object_set_big_32;
743 set_64 = simple_object_set_big_64;
745 memset (hdr, 0, sizeof (struct external_filehdr));
747 set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
748 set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
749 /* f_timdat left as zero. */
750 if (u64)
752 set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
753 symtab_offset);
754 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
755 nsyms);
756 /* f_opthdr left as zero. */
757 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
758 attrs->flags);
760 else
762 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
763 symtab_offset);
764 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
765 nsyms);
766 /* f_opthdr left as zero. */
767 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
768 attrs->flags);
771 return simple_object_internal_write (descriptor, 0, hdrbuf,
772 sizeof (struct external_filehdr),
773 errmsg, err);
776 /* Write out a XCOFF section header. */
778 static int
779 simple_object_xcoff_write_scnhdr (simple_object_write *sobj,
780 int descriptor,
781 const char *name, size_t *name_offset,
782 off_t scnhdr_offset, size_t scnsize,
783 off_t offset, unsigned int align,
784 const char **errmsg, int *err)
786 struct simple_object_xcoff_read *ocr =
787 (struct simple_object_xcoff_read *) sobj->data;
788 int u64 = ocr->magic == U64_TOCMAGIC;
789 void (*set_32) (unsigned char *, unsigned int);
790 void (*set_64) (unsigned char *, unsigned int);
791 unsigned char hdrbuf[sizeof (struct external_scnhdr)];
792 unsigned char *hdr;
793 size_t namelen;
794 unsigned int flags;
796 set_32 = simple_object_set_big_32;
797 set_64 = simple_object_set_big_32;
799 memset (hdrbuf, 0, sizeof hdrbuf);
800 hdr = &hdrbuf[0];
802 namelen = strlen (name);
803 if (namelen <= SCNNMLEN)
804 strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name),
805 name, SCNNMLEN);
806 else
808 snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
809 SCNNMLEN, "/%lu", (unsigned long) *name_offset);
810 *name_offset += namelen + 1;
813 /* s_paddr left as zero. */
814 /* s_vaddr left as zero. */
815 if (u64)
817 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size),
818 scnsize);
819 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr),
820 offset);
822 else
824 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size),
825 scnsize);
826 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr),
827 offset);
829 /* s_relptr left as zero. */
830 /* s_lnnoptr left as zero. */
831 /* s_nreloc left as zero. */
832 /* s_nlnno left as zero. */
833 flags = STYP_DATA;
834 if (align > 13)
835 align = 13;
836 if (u64)
837 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags);
838 else
839 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags);
841 return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
842 u64 ? SCNHSZ64 : SCNHSZ32,
843 errmsg, err);
846 /* Write out a complete XCOFF file. */
848 static const char *
849 simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor,
850 int *err)
852 struct simple_object_xcoff_read *ocr =
853 (struct simple_object_xcoff_read *) sobj->data;
854 int u64 = ocr->magic == U64_TOCMAGIC;
855 unsigned int nscns, secnum;
856 simple_object_write_section *section;
857 off_t scnhdr_offset;
858 size_t symtab_offset;
859 off_t secsym_offset;
860 unsigned int nsyms;
861 size_t offset;
862 size_t name_offset;
863 const char *errmsg;
864 unsigned char strsizebuf[4];
865 /* The interface doesn't give us access to the name of the input file
866 yet. We want to use its basename for the FILE symbol. This is
867 what 'gas' uses when told to assemble from stdin. */
868 const char *source_filename = "fake";
869 size_t sflen;
870 union
872 struct external_syment sym;
873 union external_auxent aux;
874 } syms[2];
875 void (*set_16) (unsigned char *, unsigned short);
876 void (*set_32) (unsigned char *, unsigned int);
878 set_16 = simple_object_set_big_16;
879 set_32 = simple_object_set_big_32;
881 nscns = 0;
882 for (section = sobj->sections; section != NULL; section = section->next)
883 ++nscns;
885 scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0);
886 offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32);
887 name_offset = 4;
888 for (section = sobj->sections; section != NULL; section = section->next)
890 size_t mask;
891 size_t new_offset;
892 size_t scnsize;
893 struct simple_object_write_section_buffer *buffer;
895 mask = (1U << section->align) - 1;
896 new_offset = offset & mask;
897 new_offset &= ~ mask;
898 while (new_offset > offset)
900 unsigned char zeroes[16];
901 size_t write;
903 memset (zeroes, 0, sizeof zeroes);
904 write = new_offset - offset;
905 if (write > sizeof zeroes)
906 write = sizeof zeroes;
907 if (!simple_object_internal_write (descriptor, offset, zeroes, write,
908 &errmsg, err))
909 return errmsg;
912 scnsize = 0;
913 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
915 if (!simple_object_internal_write (descriptor, offset + scnsize,
916 ((const unsigned char *)
917 buffer->buffer),
918 buffer->size, &errmsg, err))
919 return errmsg;
920 scnsize += buffer->size;
923 if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name,
924 &name_offset, scnhdr_offset,
925 scnsize, offset, section->align,
926 &errmsg, err))
927 return errmsg;
929 scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32;
930 offset += scnsize;
933 /* Symbol table is always half-word aligned. */
934 offset += (offset & 1);
935 /* There is a file symbol and a section symbol per section,
936 and each of these has a single auxiliary symbol following. */
937 nsyms = 2 * (nscns + 1);
938 symtab_offset = offset;
939 /* Advance across space reserved for symbol table to locate
940 start of string table. */
941 offset += nsyms * SYMESZ;
943 /* Write out file symbol. */
944 memset (&syms[0], 0, sizeof (syms));
945 if (!u64)
946 strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file");
947 set_16 (&syms[0].sym.n_scnum[0], N_DEBUG);
948 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
949 syms[0].sym.n_sclass[0] = C_FILE;
950 syms[0].sym.n_numaux[0] = 1;
951 /* The name need not be nul-terminated if it fits into the x_fname field
952 directly, but must be if it has to be placed into the string table. */
953 sflen = strlen (source_filename);
954 if (sflen <= FILNMLEN)
955 memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
956 else
958 set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset);
959 if (!simple_object_internal_write (descriptor, offset + name_offset,
960 ((const unsigned char *)
961 source_filename),
962 sflen + 1, &errmsg, err))
963 return errmsg;
964 name_offset += strlen (source_filename) + 1;
966 if (!simple_object_internal_write (descriptor, symtab_offset,
967 (const unsigned char *) &syms[0],
968 sizeof (syms), &errmsg, err))
969 return errmsg;
971 /* Write the string table length, followed by the strings and section
972 symbols in step with each other. */
973 set_32 (strsizebuf, name_offset);
974 if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
975 &errmsg, err))
976 return errmsg;
978 name_offset = 4;
979 secsym_offset = symtab_offset + sizeof (syms);
980 memset (&syms[0], 0, sizeof (syms));
981 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
982 syms[0].sym.n_sclass[0] = C_STAT;
983 syms[0].sym.n_numaux[0] = 1;
984 secnum = 1;
986 for (section = sobj->sections; section != NULL; section = section->next)
988 size_t namelen;
989 size_t scnsize;
990 struct simple_object_write_section_buffer *buffer;
992 namelen = strlen (section->name);
993 set_16 (&syms[0].sym.n_scnum[0], secnum++);
994 scnsize = 0;
995 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
996 scnsize += buffer->size;
997 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
998 if (namelen > SCNNMLEN)
1000 set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0);
1001 set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset);
1002 if (!simple_object_internal_write (descriptor, offset + name_offset,
1003 ((const unsigned char *)
1004 section->name),
1005 namelen + 1, &errmsg, err))
1006 return errmsg;
1007 name_offset += namelen + 1;
1009 else
1011 memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name,
1012 strlen (section->name));
1013 memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0,
1014 N_SYMNMLEN - strlen (section->name));
1017 if (!simple_object_internal_write (descriptor, secsym_offset,
1018 (const unsigned char *) &syms[0],
1019 sizeof (syms), &errmsg, err))
1020 return errmsg;
1021 secsym_offset += sizeof (syms);
1024 if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns,
1025 symtab_offset, nsyms, &errmsg, err))
1026 return errmsg;
1028 return NULL;
1031 /* Release the private data for an simple_object_write structure. */
1033 static void
1034 simple_object_xcoff_release_write (void *data)
1036 XDELETE (data);
1039 /* The XCOFF functions. */
1041 const struct simple_object_functions simple_object_xcoff_functions =
1043 simple_object_xcoff_match,
1044 simple_object_xcoff_find_sections,
1045 simple_object_xcoff_fetch_attributes,
1046 simple_object_xcoff_release_read,
1047 simple_object_xcoff_attributes_merge,
1048 simple_object_xcoff_release_attributes,
1049 simple_object_xcoff_start_write,
1050 simple_object_xcoff_write_to_file,
1051 simple_object_xcoff_release_write,
1052 NULL