]> git.ipfire.org Git - thirdparty/gcc.git/blob - libiberty/simple-object-xcoff.c
2017-06-07 Tony Reix <tony.reix@atos.net>
[thirdparty/gcc.git] / libiberty / simple-object-xcoff.c
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.
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 /* XCOFF structures and constants. */
46
47 /* XCOFF 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 union
55 {
56 struct
57 {
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
64 {
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;
71 };
72
73 /* Bits for filehdr f_flags field. */
74
75 #define F_EXEC (0x0002)
76
77 /* The known values of f_magic in an XCOFF file header. */
78
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. */
84
85 /* XCOFF section header. */
86
87 struct external_scnhdr
88 {
89 unsigned char s_name[8]; /* section name */
90 union
91 {
92 struct
93 {
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
105 {
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;
117 };
118
119 #define SCNHSZ32 (40)
120 #define SCNHSZ64 (68)
121
122 /* The length of the s_name field in struct external_scnhdr. */
123
124 #define SCNNMLEN (8)
125
126 /* Bits for scnhdr s_flags field. */
127
128 #define STYP_DATA 0x40
129
130 /* XCOFF symbol table entry. */
131
132
133 #define N_SYMNMLEN (8) /* # characters in a symbol name */
134
135 /* The format of an XCOFF symbol-table entry. */
136 struct external_syment
137 {
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;
151
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];
158
159 /* The offset of the symbol from the start of the string table. */
160 unsigned char n_offset[4];
161 } xcoff64;
162 } u;
163
164 /* The number of the section to which this symbol belongs. */
165 unsigned char n_scnum[2];
166
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];
170
171 /* The class of symbol (a C_* value). */
172 unsigned char n_sclass[1];
173
174 /* The number of auxiliary symbols attached to this entry. */
175 unsigned char n_numaux[1];
176 };
177
178 #define SYMESZ (18)
179
180 /* Length allowed for filename in aux sym format 4. */
181
182 #define FILNMLEN (14)
183
184 /* Omits x_sym and other unused variants. */
185
186 union external_auxent
187 {
188 /* Aux sym format 4: file. */
189 union
190 {
191 char x_fname[FILNMLEN];
192 struct
193 {
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
202 {
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
209 {
210 struct
211 {
212 struct
213 {
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
224 {
225 struct
226 {
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
240 {
241 unsigned char x_scnlen[4]; /* section length */
242 unsigned char pad1[4];
243 unsigned char x_nreloc[4]; /* number RLDs */
244 } x_sect;
245 };
246
247 /* Symbol-related constants. */
248
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)
254
255 #define IMAGE_SYM_TYPE \
256 ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
257
258 #define C_STAT (3)
259 #define C_FILE (103)
260
261 #define DBXMASK 0x80
262
263 /* Private data for an simple_object_read. */
264
265 struct simple_object_xcoff_read
266 {
267 /* Magic number. */
268 unsigned short magic;
269 /* Number of sections. */
270 unsigned short nscns;
271 /* File offset of symbol table. */
272 off_t symptr;
273 /* Number of symbol table entries. */
274 unsigned int nsyms;
275 /* Flags. */
276 unsigned short flags;
277 /* Offset of section headers in file. */
278 off_t scnhdr_offset;
279 };
280
281 /* Private data for an simple_object_attributes. */
282
283 struct simple_object_xcoff_attributes
284 {
285 /* Magic number. */
286 unsigned short magic;
287 /* Flags. */
288 unsigned short flags;
289 };
290
291 /* See if we have a XCOFF file. */
292
293 static void *
294 simple_object_xcoff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
295 int descriptor, off_t offset,
296 const char *segment_name ATTRIBUTE_UNUSED,
297 const char **errmsg, int *err)
298 {
299 unsigned short magic;
300 unsigned short (*fetch_16) (const unsigned char *);
301 unsigned int (*fetch_32) (const unsigned char *);
302 ulong_type (*fetch_64) (const unsigned char *);
303 unsigned char hdrbuf[sizeof (struct external_filehdr)];
304 struct simple_object_xcoff_read *ocr;
305 int u64;
306
307 magic = simple_object_fetch_big_16 (header);
308
309 if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC)
310 {
311 *errmsg = NULL;
312 *err = 0;
313 return NULL;
314 }
315
316 fetch_16 = simple_object_fetch_big_16;
317 fetch_32 = simple_object_fetch_big_32;
318 fetch_64 = simple_object_fetch_big_64;
319
320 if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
321 errmsg, err))
322 return NULL;
323
324 u64 = magic == U64_TOCMAGIC;
325
326 ocr = XNEW (struct simple_object_xcoff_read);
327 ocr->magic = magic;
328 ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
329 if (u64)
330 {
331 ocr->symptr = fetch_64 (hdrbuf
332 + offsetof (struct external_filehdr,
333 u.xcoff64.f_symptr));
334 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
335 u.xcoff64.f_nsyms));
336 ocr->scnhdr_offset = (sizeof (struct external_filehdr)
337 + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
338 u.xcoff64.f_opthdr)));
339
340 }
341 else
342 {
343 ocr->symptr = fetch_32 (hdrbuf
344 + offsetof (struct external_filehdr,
345 u.xcoff32.f_symptr));
346 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
347 u.xcoff32.f_nsyms));
348 ocr->scnhdr_offset = (sizeof (struct external_filehdr) - 4
349 + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
350 u.xcoff32.f_opthdr)));
351
352 }
353
354 return (void *) ocr;
355 }
356
357 /* Read the string table in a XCOFF file. */
358
359 static char *
360 simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
361 const char **errmsg, int *err)
362 {
363 struct simple_object_xcoff_read *ocr =
364 (struct simple_object_xcoff_read *) sobj->data;
365 off_t strtab_offset;
366 unsigned char strsizebuf[4];
367 size_t strsize;
368 char *strtab;
369
370 strtab_offset = sobj->offset + ocr->symptr
371 + ocr->nsyms * SYMESZ;
372 if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
373 strsizebuf, 4, errmsg, err))
374 return NULL;
375 strsize = simple_object_fetch_big_32 (strsizebuf);
376 strtab = XNEWVEC (char, strsize);
377 if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
378 (unsigned char *) strtab, strsize, errmsg,
379 err))
380 {
381 XDELETEVEC (strtab);
382 return NULL;
383 }
384 *strtab_size = strsize;
385 return strtab;
386 }
387
388 /* Find all sections in a XCOFF file. */
389
390 static const char *
391 simple_object_xcoff_find_sections (simple_object_read *sobj,
392 int (*pfn) (void *, const char *,
393 off_t offset, off_t length),
394 void *data,
395 int *err)
396 {
397 struct simple_object_xcoff_read *ocr =
398 (struct simple_object_xcoff_read *) sobj->data;
399 int u64 = ocr->magic == U64_TOCMAGIC;
400 size_t scnhdr_size;
401 unsigned char *scnbuf;
402 const char *errmsg;
403 unsigned int (*fetch_32) (const unsigned char *);
404 ulong_type (*fetch_64) (const unsigned char *);
405 unsigned int nscns;
406 char *strtab;
407 size_t strtab_size;
408 struct external_syment *symtab = NULL;
409 unsigned int i;
410 off_t textptr = 0;
411
412 scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32;
413 scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
414 if (!simple_object_internal_read (sobj->descriptor,
415 sobj->offset + ocr->scnhdr_offset,
416 scnbuf, scnhdr_size * ocr->nscns, &errmsg,
417 err))
418 {
419 XDELETEVEC (scnbuf);
420 return errmsg;
421 }
422
423 fetch_32 = simple_object_fetch_big_32;
424 fetch_64 = simple_object_fetch_big_64;
425
426 nscns = ocr->nscns;
427 strtab = NULL;
428 strtab_size = 0;
429 for (i = 0; i < nscns; ++i)
430 {
431 unsigned char *scnhdr;
432 unsigned char *scnname;
433 char namebuf[SCNNMLEN + 1];
434 char *name;
435 off_t scnptr;
436 unsigned int size;
437
438 scnhdr = scnbuf + i * scnhdr_size;
439 scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
440 memcpy (namebuf, scnname, SCNNMLEN);
441 namebuf[SCNNMLEN] = '\0';
442 name = &namebuf[0];
443 if (namebuf[0] == '/')
444 {
445 size_t strindex;
446 char *end;
447
448 strindex = strtol (namebuf + 1, &end, 10);
449 if (*end == '\0')
450 {
451 /* The real section name is found in the string
452 table. */
453 if (strtab == NULL)
454 {
455 strtab = simple_object_xcoff_read_strtab (sobj,
456 &strtab_size,
457 &errmsg, err);
458 if (strtab == NULL)
459 {
460 XDELETEVEC (scnbuf);
461 return errmsg;
462 }
463 }
464
465 if (strindex < 4 || strindex >= strtab_size)
466 {
467 XDELETEVEC (strtab);
468 XDELETEVEC (scnbuf);
469 *err = 0;
470 return "section string index out of range";
471 }
472
473 name = strtab + strindex;
474 }
475 }
476
477 if (u64)
478 {
479 scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
480 u.xcoff64.s_scnptr));
481 size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
482 u.xcoff64.s_size));
483 }
484 else
485 {
486 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
487 u.xcoff32.s_scnptr));
488 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
489 u.xcoff32.s_size));
490 }
491
492 if (strcmp (name, ".text") == 0)
493 textptr = scnptr;
494 if (!(*pfn) (data, name, scnptr, size))
495 break;
496 }
497
498 /* Special handling for .go_export CSECT. */
499 if (textptr != 0 && ocr->nsyms > 0)
500 {
501 unsigned char *sym, *aux;
502 const char *n_name;
503 unsigned long n_value, n_offset, n_zeroes, x_scnlen;
504
505 /* Read symbol table. */
506 symtab = XNEWVEC (struct external_syment, ocr->nsyms * SYMESZ);
507 if (!simple_object_internal_read (sobj->descriptor,
508 sobj->offset + ocr->symptr,
509 (unsigned char *)symtab,
510 ocr->nsyms * SYMESZ,
511 &errmsg, err))
512 {
513 XDELETEVEC (symtab);
514 XDELETEVEC (scnbuf);
515 return NULL;
516 }
517
518 /* Search in symbol table if we have a ".go_export" symbol. */
519 for (i = 0; i < ocr->nsyms; ++i)
520 {
521 sym = (unsigned char *)&symtab[i];
522
523 if (symtab[i].n_sclass[0] & DBXMASK)
524 {
525 /* Skip debug symbols whose names are in stabs. */
526 i += symtab[i].n_numaux[0];
527 continue;
528 }
529 if (u64)
530 {
531 n_value = fetch_64 (sym + offsetof (struct external_syment,
532 u.xcoff64.n_value));
533 n_offset = fetch_32 (sym + offsetof (struct external_syment,
534 u.xcoff64.n_offset));
535 }
536 else
537 {
538 /* ".go_export" is longer than N_SYMNMLEN */
539 n_zeroes = fetch_32 (sym + offsetof (struct external_syment,
540 u.xcoff32.n.n.n_zeroes));
541 if (n_zeroes != 0)
542 {
543 /* Skip auxiliary entries. */
544 i += symtab[i].n_numaux[0];
545 continue;
546 }
547 n_value = fetch_32 (sym + offsetof (struct external_syment,
548 u.xcoff32.n_value));
549 n_offset = fetch_32 (sym + offsetof (struct external_syment,
550 u.xcoff32.n.n.n_offset));
551 }
552
553 /* The real section name is found in the string table. */
554 if (strtab == NULL)
555 {
556 strtab = simple_object_xcoff_read_strtab (sobj,
557 &strtab_size,
558 &errmsg, err);
559 if (strtab == NULL)
560 {
561 XDELETEVEC (symtab);
562 XDELETEVEC (scnbuf);
563 return errmsg;
564 }
565 }
566
567 if (n_offset >= strtab_size)
568 {
569 XDELETEVEC (strtab);
570 XDELETEVEC (symtab);
571 XDELETEVEC (scnbuf);
572 *err = 0;
573 return "section string index out of range";
574 }
575 n_name = strtab + n_offset;
576
577 if (!strcmp(n_name, ".go_export"))
578 {
579 /* Found .go_export symbol, read auxiliary entry. */
580 if (i + 1 >= ocr->nsyms)
581 break;
582
583 aux = (unsigned char *)&symtab[i + 1];
584 if (u64)
585 {
586 x_scnlen = fetch_32 (aux + offsetof (union external_auxent,
587 u.xcoff64.x_csect.x_scnlen_lo));
588 }
589 else
590 {
591 x_scnlen = fetch_32 (aux + offsetof (union external_auxent,
592 u.xcoff32.x_csect.x_scnlen));
593 }
594 (*pfn) (data, ".go_export", textptr + n_value, x_scnlen);
595 break;
596 }
597 /* Skip auxiliary entries. */
598 i += symtab[i].n_numaux[0];
599 }
600 }
601
602 if (symtab != NULL)
603 XDELETEVEC (symtab);
604 if (strtab != NULL)
605 XDELETEVEC (strtab);
606 XDELETEVEC (scnbuf);
607
608 return NULL;
609 }
610
611 /* Fetch the attributes for an simple_object_read. */
612
613 static void *
614 simple_object_xcoff_fetch_attributes (simple_object_read *sobj,
615 const char **errmsg ATTRIBUTE_UNUSED,
616 int *err ATTRIBUTE_UNUSED)
617 {
618 struct simple_object_xcoff_read *ocr =
619 (struct simple_object_xcoff_read *) sobj->data;
620 struct simple_object_xcoff_attributes *ret;
621
622 ret = XNEW (struct simple_object_xcoff_attributes);
623 ret->magic = ocr->magic;
624 ret->flags = ocr->flags;
625 return ret;
626 }
627
628 /* Release the private data for an simple_object_read. */
629
630 static void
631 simple_object_xcoff_release_read (void *data)
632 {
633 XDELETE (data);
634 }
635
636 /* Compare two attributes structures. */
637
638 static const char *
639 simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err)
640 {
641 struct simple_object_xcoff_attributes *to =
642 (struct simple_object_xcoff_attributes *) todata;
643 struct simple_object_xcoff_attributes *from =
644 (struct simple_object_xcoff_attributes *) fromdata;
645
646 if (to->magic != from->magic)
647 {
648 *err = 0;
649 return "XCOFF object format mismatch";
650 }
651 return NULL;
652 }
653
654 /* Release the private data for an attributes structure. */
655
656 static void
657 simple_object_xcoff_release_attributes (void *data)
658 {
659 XDELETE (data);
660 }
661
662 /* Prepare to write out a file. */
663
664 static void *
665 simple_object_xcoff_start_write (void *attributes_data,
666 const char **errmsg ATTRIBUTE_UNUSED,
667 int *err ATTRIBUTE_UNUSED)
668 {
669 struct simple_object_xcoff_attributes *attrs =
670 (struct simple_object_xcoff_attributes *) attributes_data;
671 struct simple_object_xcoff_attributes *ret;
672
673 /* We're just going to record the attributes, but we need to make a
674 copy because the user may delete them. */
675 ret = XNEW (struct simple_object_xcoff_attributes);
676 *ret = *attrs;
677 return ret;
678 }
679
680 /* Write out a XCOFF filehdr. */
681
682 static int
683 simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor,
684 unsigned int nscns, size_t symtab_offset,
685 unsigned int nsyms, const char **errmsg,
686 int *err)
687 {
688 struct simple_object_xcoff_attributes *attrs =
689 (struct simple_object_xcoff_attributes *) sobj->data;
690 int u64 = attrs->magic == U64_TOCMAGIC;
691 unsigned char hdrbuf[sizeof (struct external_filehdr)];
692 unsigned char *hdr;
693 void (*set_16) (unsigned char *, unsigned short);
694 void (*set_32) (unsigned char *, unsigned int);
695 void (*set_64) (unsigned char *, ulong_type);
696
697 hdr = &hdrbuf[0];
698
699 set_16 = simple_object_set_big_16;
700 set_32 = simple_object_set_big_32;
701 set_64 = simple_object_set_big_64;
702
703 memset (hdr, 0, sizeof (struct external_filehdr));
704
705 set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
706 set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
707 /* f_timdat left as zero. */
708 if (u64)
709 {
710 set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
711 symtab_offset);
712 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
713 nsyms);
714 /* f_opthdr left as zero. */
715 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
716 attrs->flags);
717 }
718 else
719 {
720 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
721 symtab_offset);
722 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
723 nsyms);
724 /* f_opthdr left as zero. */
725 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
726 attrs->flags);
727 }
728
729 return simple_object_internal_write (descriptor, 0, hdrbuf,
730 sizeof (struct external_filehdr),
731 errmsg, err);
732 }
733
734 /* Write out a XCOFF section header. */
735
736 static int
737 simple_object_xcoff_write_scnhdr (simple_object_write *sobj,
738 int descriptor,
739 const char *name, size_t *name_offset,
740 off_t scnhdr_offset, size_t scnsize,
741 off_t offset, unsigned int align,
742 const char **errmsg, int *err)
743 {
744 struct simple_object_xcoff_read *ocr =
745 (struct simple_object_xcoff_read *) sobj->data;
746 int u64 = ocr->magic == U64_TOCMAGIC;
747 void (*set_32) (unsigned char *, unsigned int);
748 void (*set_64) (unsigned char *, unsigned int);
749 unsigned char hdrbuf[sizeof (struct external_scnhdr)];
750 unsigned char *hdr;
751 size_t namelen;
752 unsigned int flags;
753
754 set_32 = simple_object_set_big_32;
755 set_64 = simple_object_set_big_32;
756
757 memset (hdrbuf, 0, sizeof hdrbuf);
758 hdr = &hdrbuf[0];
759
760 namelen = strlen (name);
761 if (namelen <= SCNNMLEN)
762 strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name),
763 name, SCNNMLEN);
764 else
765 {
766 snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
767 SCNNMLEN, "/%lu", (unsigned long) *name_offset);
768 *name_offset += namelen + 1;
769 }
770
771 /* s_paddr left as zero. */
772 /* s_vaddr left as zero. */
773 if (u64)
774 {
775 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size),
776 scnsize);
777 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr),
778 offset);
779 }
780 else
781 {
782 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size),
783 scnsize);
784 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr),
785 offset);
786 }
787 /* s_relptr left as zero. */
788 /* s_lnnoptr left as zero. */
789 /* s_nreloc left as zero. */
790 /* s_nlnno left as zero. */
791 flags = STYP_DATA;
792 if (align > 13)
793 align = 13;
794 if (u64)
795 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags);
796 else
797 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags);
798
799 return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
800 u64 ? SCNHSZ64 : SCNHSZ32,
801 errmsg, err);
802 }
803
804 /* Write out a complete XCOFF file. */
805
806 static const char *
807 simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor,
808 int *err)
809 {
810 struct simple_object_xcoff_read *ocr =
811 (struct simple_object_xcoff_read *) sobj->data;
812 int u64 = ocr->magic == U64_TOCMAGIC;
813 unsigned int nscns, secnum;
814 simple_object_write_section *section;
815 off_t scnhdr_offset;
816 size_t symtab_offset;
817 off_t secsym_offset;
818 unsigned int nsyms;
819 size_t offset;
820 size_t name_offset;
821 const char *errmsg;
822 unsigned char strsizebuf[4];
823 /* The interface doesn't give us access to the name of the input file
824 yet. We want to use its basename for the FILE symbol. This is
825 what 'gas' uses when told to assemble from stdin. */
826 const char *source_filename = "fake";
827 size_t sflen;
828 union
829 {
830 struct external_syment sym;
831 union external_auxent aux;
832 } syms[2];
833 void (*set_16) (unsigned char *, unsigned short);
834 void (*set_32) (unsigned char *, unsigned int);
835
836 set_16 = simple_object_set_big_16;
837 set_32 = simple_object_set_big_32;
838
839 nscns = 0;
840 for (section = sobj->sections; section != NULL; section = section->next)
841 ++nscns;
842
843 scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0);
844 offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32);
845 name_offset = 4;
846 for (section = sobj->sections; section != NULL; section = section->next)
847 {
848 size_t mask;
849 size_t new_offset;
850 size_t scnsize;
851 struct simple_object_write_section_buffer *buffer;
852
853 mask = (1U << section->align) - 1;
854 new_offset = offset & mask;
855 new_offset &= ~ mask;
856 while (new_offset > offset)
857 {
858 unsigned char zeroes[16];
859 size_t write;
860
861 memset (zeroes, 0, sizeof zeroes);
862 write = new_offset - offset;
863 if (write > sizeof zeroes)
864 write = sizeof zeroes;
865 if (!simple_object_internal_write (descriptor, offset, zeroes, write,
866 &errmsg, err))
867 return errmsg;
868 }
869
870 scnsize = 0;
871 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
872 {
873 if (!simple_object_internal_write (descriptor, offset + scnsize,
874 ((const unsigned char *)
875 buffer->buffer),
876 buffer->size, &errmsg, err))
877 return errmsg;
878 scnsize += buffer->size;
879 }
880
881 if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name,
882 &name_offset, scnhdr_offset,
883 scnsize, offset, section->align,
884 &errmsg, err))
885 return errmsg;
886
887 scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32;
888 offset += scnsize;
889 }
890
891 /* Symbol table is always half-word aligned. */
892 offset += (offset & 1);
893 /* There is a file symbol and a section symbol per section,
894 and each of these has a single auxiliary symbol following. */
895 nsyms = 2 * (nscns + 1);
896 symtab_offset = offset;
897 /* Advance across space reserved for symbol table to locate
898 start of string table. */
899 offset += nsyms * SYMESZ;
900
901 /* Write out file symbol. */
902 memset (&syms[0], 0, sizeof (syms));
903 if (!u64)
904 strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file");
905 set_16 (&syms[0].sym.n_scnum[0], N_DEBUG);
906 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
907 syms[0].sym.n_sclass[0] = C_FILE;
908 syms[0].sym.n_numaux[0] = 1;
909 /* The name need not be nul-terminated if it fits into the x_fname field
910 directly, but must be if it has to be placed into the string table. */
911 sflen = strlen (source_filename);
912 if (sflen <= FILNMLEN)
913 memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
914 else
915 {
916 set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset);
917 if (!simple_object_internal_write (descriptor, offset + name_offset,
918 ((const unsigned char *)
919 source_filename),
920 sflen + 1, &errmsg, err))
921 return errmsg;
922 name_offset += strlen (source_filename) + 1;
923 }
924 if (!simple_object_internal_write (descriptor, symtab_offset,
925 (const unsigned char *) &syms[0],
926 sizeof (syms), &errmsg, err))
927 return errmsg;
928
929 /* Write the string table length, followed by the strings and section
930 symbols in step with each other. */
931 set_32 (strsizebuf, name_offset);
932 if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
933 &errmsg, err))
934 return errmsg;
935
936 name_offset = 4;
937 secsym_offset = symtab_offset + sizeof (syms);
938 memset (&syms[0], 0, sizeof (syms));
939 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
940 syms[0].sym.n_sclass[0] = C_STAT;
941 syms[0].sym.n_numaux[0] = 1;
942 secnum = 1;
943
944 for (section = sobj->sections; section != NULL; section = section->next)
945 {
946 size_t namelen;
947 size_t scnsize;
948 struct simple_object_write_section_buffer *buffer;
949
950 namelen = strlen (section->name);
951 set_16 (&syms[0].sym.n_scnum[0], secnum++);
952 scnsize = 0;
953 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
954 scnsize += buffer->size;
955 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
956 if (namelen > SCNNMLEN)
957 {
958 set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0);
959 set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset);
960 if (!simple_object_internal_write (descriptor, offset + name_offset,
961 ((const unsigned char *)
962 section->name),
963 namelen + 1, &errmsg, err))
964 return errmsg;
965 name_offset += namelen + 1;
966 }
967 else
968 {
969 memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name,
970 strlen (section->name));
971 memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0,
972 N_SYMNMLEN - strlen (section->name));
973 }
974
975 if (!simple_object_internal_write (descriptor, secsym_offset,
976 (const unsigned char *) &syms[0],
977 sizeof (syms), &errmsg, err))
978 return errmsg;
979 secsym_offset += sizeof (syms);
980 }
981
982 if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns,
983 symtab_offset, nsyms, &errmsg, err))
984 return errmsg;
985
986 return NULL;
987 }
988
989 /* Release the private data for an simple_object_write structure. */
990
991 static void
992 simple_object_xcoff_release_write (void *data)
993 {
994 XDELETE (data);
995 }
996
997 /* The XCOFF functions. */
998
999 const struct simple_object_functions simple_object_xcoff_functions =
1000 {
1001 simple_object_xcoff_match,
1002 simple_object_xcoff_find_sections,
1003 simple_object_xcoff_fetch_attributes,
1004 simple_object_xcoff_release_read,
1005 simple_object_xcoff_attributes_merge,
1006 simple_object_xcoff_release_attributes,
1007 simple_object_xcoff_start_write,
1008 simple_object_xcoff_write_to_file,
1009 simple_object_xcoff_release_write
1010 };