1 /* simple-object-coff.c -- routines to manipulate XCOFF object files.
2 Copyright 2013 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 /* Private data for an simple_object_read. */
262
263 struct simple_object_xcoff_read
264 {
265 /* Magic number. */
266 unsigned short magic;
267 /* Number of sections. */
268 unsigned short nscns;
269 /* File offset of symbol table. */
270 off_t symptr;
271 /* Number of symbol table entries. */
272 unsigned int nsyms;
273 /* Flags. */
274 unsigned short flags;
275 /* Offset of section headers in file. */
276 off_t scnhdr_offset;
277 };
278
279 /* Private data for an simple_object_attributes. */
280
281 struct simple_object_xcoff_attributes
282 {
283 /* Magic number. */
284 unsigned short magic;
285 /* Flags. */
286 unsigned short flags;
287 };
288
289 /* See if we have a XCOFF file. */
290
291 static void *
simple_object_xcoff_match(unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],int descriptor,off_t offset,const char * segment_name ATTRIBUTE_UNUSED,const char ** errmsg,int * err)292 simple_object_xcoff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
293 int descriptor, off_t offset,
294 const char *segment_name ATTRIBUTE_UNUSED,
295 const char **errmsg, int *err)
296 {
297 unsigned short magic;
298 unsigned short (*fetch_16) (const unsigned char *);
299 unsigned int (*fetch_32) (const unsigned char *);
300 ulong_type (*fetch_64) (const unsigned char *);
301 unsigned char hdrbuf[sizeof (struct external_filehdr)];
302 struct simple_object_xcoff_read *ocr;
303 int u64;
304
305 magic = simple_object_fetch_big_16 (header);
306
307 if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC)
308 {
309 *errmsg = NULL;
310 *err = 0;
311 return NULL;
312 }
313
314 fetch_16 = simple_object_fetch_big_16;
315 fetch_32 = simple_object_fetch_big_32;
316 fetch_64 = simple_object_fetch_big_64;
317
318 if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
319 errmsg, err))
320 return NULL;
321
322 u64 = magic == U64_TOCMAGIC;
323
324 ocr = XNEW (struct simple_object_xcoff_read);
325 ocr->magic = magic;
326 ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
327 if (u64)
328 {
329 ocr->symptr = fetch_64 (hdrbuf
330 + offsetof (struct external_filehdr,
331 u.xcoff64.f_symptr));
332 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
333 u.xcoff64.f_nsyms));
334 ocr->scnhdr_offset = (sizeof (struct external_filehdr)
335 + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
336 u.xcoff64.f_opthdr)));
337
338 }
339 else
340 {
341 ocr->symptr = fetch_32 (hdrbuf
342 + offsetof (struct external_filehdr,
343 u.xcoff32.f_symptr));
344 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
345 u.xcoff32.f_nsyms));
346 ocr->scnhdr_offset = (sizeof (struct external_filehdr) - 4
347 + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
348 u.xcoff32.f_opthdr)));
349
350 }
351
352 return (void *) ocr;
353 }
354
355 /* Read the string table in a XCOFF file. */
356
357 static char *
simple_object_xcoff_read_strtab(simple_object_read * sobj,size_t * strtab_size,const char ** errmsg,int * err)358 simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
359 const char **errmsg, int *err)
360 {
361 struct simple_object_xcoff_read *ocr =
362 (struct simple_object_xcoff_read *) sobj->data;
363 off_t strtab_offset;
364 unsigned char strsizebuf[4];
365 size_t strsize;
366 char *strtab;
367
368 strtab_offset = sobj->offset + ocr->symptr
369 + ocr->nsyms * SYMESZ;
370 if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
371 strsizebuf, 4, errmsg, err))
372 return NULL;
373 strsize = simple_object_fetch_big_32 (strsizebuf);
374 strtab = XNEWVEC (char, strsize);
375 if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
376 (unsigned char *) strtab, strsize, errmsg,
377 err))
378 {
379 XDELETEVEC (strtab);
380 return NULL;
381 }
382 *strtab_size = strsize;
383 return strtab;
384 }
385
386 /* Find all sections in a XCOFF file. */
387
388 static const char *
simple_object_xcoff_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t offset,off_t length),void * data,int * err)389 simple_object_xcoff_find_sections (simple_object_read *sobj,
390 int (*pfn) (void *, const char *,
391 off_t offset, off_t length),
392 void *data,
393 int *err)
394 {
395 struct simple_object_xcoff_read *ocr =
396 (struct simple_object_xcoff_read *) sobj->data;
397 int u64 = ocr->magic == U64_TOCMAGIC;
398 size_t scnhdr_size;
399 unsigned char *scnbuf;
400 const char *errmsg;
401 unsigned int (*fetch_32) (const unsigned char *);
402 ulong_type (*fetch_64) (const unsigned char *);
403 unsigned int nscns;
404 char *strtab;
405 size_t strtab_size;
406 unsigned int i;
407
408 scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32;
409 scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
410 if (!simple_object_internal_read (sobj->descriptor,
411 sobj->offset + ocr->scnhdr_offset,
412 scnbuf, scnhdr_size * ocr->nscns, &errmsg,
413 err))
414 {
415 XDELETEVEC (scnbuf);
416 return errmsg;
417 }
418
419 fetch_32 = simple_object_fetch_big_32;
420 fetch_64 = simple_object_fetch_big_64;
421
422 nscns = ocr->nscns;
423 strtab = NULL;
424 strtab_size = 0;
425 for (i = 0; i < nscns; ++i)
426 {
427 unsigned char *scnhdr;
428 unsigned char *scnname;
429 char namebuf[SCNNMLEN + 1];
430 char *name;
431 off_t scnptr;
432 unsigned int size;
433
434 scnhdr = scnbuf + i * scnhdr_size;
435 scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
436 memcpy (namebuf, scnname, SCNNMLEN);
437 namebuf[SCNNMLEN] = '\0';
438 name = &namebuf[0];
439 if (namebuf[0] == '/')
440 {
441 size_t strindex;
442 char *end;
443
444 strindex = strtol (namebuf + 1, &end, 10);
445 if (*end == '\0')
446 {
447 /* The real section name is found in the string
448 table. */
449 if (strtab == NULL)
450 {
451 strtab = simple_object_xcoff_read_strtab (sobj,
452 &strtab_size,
453 &errmsg, err);
454 if (strtab == NULL)
455 {
456 XDELETEVEC (scnbuf);
457 return errmsg;
458 }
459 }
460
461 if (strindex < 4 || strindex >= strtab_size)
462 {
463 XDELETEVEC (strtab);
464 XDELETEVEC (scnbuf);
465 *err = 0;
466 return "section string index out of range";
467 }
468
469 name = strtab + strindex;
470 }
471 }
472
473 if (u64)
474 {
475 scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
476 u.xcoff64.s_scnptr));
477 size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
478 u.xcoff64.s_size));
479 }
480 else
481 {
482 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
483 u.xcoff32.s_scnptr));
484 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
485 u.xcoff32.s_size));
486 }
487
488 if (!(*pfn) (data, name, scnptr, size))
489 break;
490 }
491
492 if (strtab != NULL)
493 XDELETEVEC (strtab);
494 XDELETEVEC (scnbuf);
495
496 return NULL;
497 }
498
499 /* Fetch the attributes for an simple_object_read. */
500
501 static void *
simple_object_xcoff_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)502 simple_object_xcoff_fetch_attributes (simple_object_read *sobj,
503 const char **errmsg ATTRIBUTE_UNUSED,
504 int *err ATTRIBUTE_UNUSED)
505 {
506 struct simple_object_xcoff_read *ocr =
507 (struct simple_object_xcoff_read *) sobj->data;
508 struct simple_object_xcoff_attributes *ret;
509
510 ret = XNEW (struct simple_object_xcoff_attributes);
511 ret->magic = ocr->magic;
512 ret->flags = ocr->flags;
513 return ret;
514 }
515
516 /* Release the private data for an simple_object_read. */
517
518 static void
simple_object_xcoff_release_read(void * data)519 simple_object_xcoff_release_read (void *data)
520 {
521 XDELETE (data);
522 }
523
524 /* Compare two attributes structures. */
525
526 static const char *
simple_object_xcoff_attributes_merge(void * todata,void * fromdata,int * err)527 simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err)
528 {
529 struct simple_object_xcoff_attributes *to =
530 (struct simple_object_xcoff_attributes *) todata;
531 struct simple_object_xcoff_attributes *from =
532 (struct simple_object_xcoff_attributes *) fromdata;
533
534 if (to->magic != from->magic)
535 {
536 *err = 0;
537 return "XCOFF object format mismatch";
538 }
539 return NULL;
540 }
541
542 /* Release the private data for an attributes structure. */
543
544 static void
simple_object_xcoff_release_attributes(void * data)545 simple_object_xcoff_release_attributes (void *data)
546 {
547 XDELETE (data);
548 }
549
550 /* Prepare to write out a file. */
551
552 static void *
simple_object_xcoff_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)553 simple_object_xcoff_start_write (void *attributes_data,
554 const char **errmsg ATTRIBUTE_UNUSED,
555 int *err ATTRIBUTE_UNUSED)
556 {
557 struct simple_object_xcoff_attributes *attrs =
558 (struct simple_object_xcoff_attributes *) attributes_data;
559 struct simple_object_xcoff_attributes *ret;
560
561 /* We're just going to record the attributes, but we need to make a
562 copy because the user may delete them. */
563 ret = XNEW (struct simple_object_xcoff_attributes);
564 *ret = *attrs;
565 return ret;
566 }
567
568 /* Write out a XCOFF filehdr. */
569
570 static int
simple_object_xcoff_write_filehdr(simple_object_write * sobj,int descriptor,unsigned int nscns,size_t symtab_offset,unsigned int nsyms,const char ** errmsg,int * err)571 simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor,
572 unsigned int nscns, size_t symtab_offset,
573 unsigned int nsyms, const char **errmsg,
574 int *err)
575 {
576 struct simple_object_xcoff_attributes *attrs =
577 (struct simple_object_xcoff_attributes *) sobj->data;
578 int u64 = attrs->magic == U64_TOCMAGIC;
579 unsigned char hdrbuf[sizeof (struct external_filehdr)];
580 unsigned char *hdr;
581 void (*set_16) (unsigned char *, unsigned short);
582 void (*set_32) (unsigned char *, unsigned int);
583 void (*set_64) (unsigned char *, ulong_type);
584
585 hdr = &hdrbuf[0];
586
587 set_16 = simple_object_set_big_16;
588 set_32 = simple_object_set_big_32;
589 set_64 = simple_object_set_big_64;
590
591 memset (hdr, 0, sizeof (struct external_filehdr));
592
593 set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
594 set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
595 /* f_timdat left as zero. */
596 if (u64)
597 {
598 set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
599 symtab_offset);
600 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
601 nsyms);
602 /* f_opthdr left as zero. */
603 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
604 attrs->flags);
605 }
606 else
607 {
608 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
609 symtab_offset);
610 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
611 nsyms);
612 /* f_opthdr left as zero. */
613 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
614 attrs->flags);
615 }
616
617 return simple_object_internal_write (descriptor, 0, hdrbuf,
618 sizeof (struct external_filehdr),
619 errmsg, err);
620 }
621
622 /* Write out a XCOFF section header. */
623
624 static int
simple_object_xcoff_write_scnhdr(simple_object_write * sobj,int descriptor,const char * name,size_t * name_offset,off_t scnhdr_offset,size_t scnsize,off_t offset,unsigned int align,const char ** errmsg,int * err)625 simple_object_xcoff_write_scnhdr (simple_object_write *sobj,
626 int descriptor,
627 const char *name, size_t *name_offset,
628 off_t scnhdr_offset, size_t scnsize,
629 off_t offset, unsigned int align,
630 const char **errmsg, int *err)
631 {
632 struct simple_object_xcoff_read *ocr =
633 (struct simple_object_xcoff_read *) sobj->data;
634 int u64 = ocr->magic == U64_TOCMAGIC;
635 void (*set_32) (unsigned char *, unsigned int);
636 void (*set_64) (unsigned char *, unsigned int);
637 unsigned char hdrbuf[sizeof (struct external_scnhdr)];
638 unsigned char *hdr;
639 size_t namelen;
640 unsigned int flags;
641
642 set_32 = simple_object_set_big_32;
643 set_64 = simple_object_set_big_32;
644
645 memset (hdrbuf, 0, sizeof hdrbuf);
646 hdr = &hdrbuf[0];
647
648 namelen = strlen (name);
649 if (namelen <= SCNNMLEN)
650 strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name),
651 name, SCNNMLEN);
652 else
653 {
654 snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
655 SCNNMLEN, "/%lu", (unsigned long) *name_offset);
656 *name_offset += namelen + 1;
657 }
658
659 /* s_paddr left as zero. */
660 /* s_vaddr left as zero. */
661 if (u64)
662 {
663 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size),
664 scnsize);
665 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr),
666 offset);
667 }
668 else
669 {
670 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size),
671 scnsize);
672 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr),
673 offset);
674 }
675 /* s_relptr left as zero. */
676 /* s_lnnoptr left as zero. */
677 /* s_nreloc left as zero. */
678 /* s_nlnno left as zero. */
679 flags = STYP_DATA;
680 if (align > 13)
681 align = 13;
682 if (u64)
683 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags);
684 else
685 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags);
686
687 return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
688 u64 ? SCNHSZ64 : SCNHSZ32,
689 errmsg, err);
690 }
691
692 /* Write out a complete XCOFF file. */
693
694 static const char *
simple_object_xcoff_write_to_file(simple_object_write * sobj,int descriptor,int * err)695 simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor,
696 int *err)
697 {
698 struct simple_object_xcoff_read *ocr =
699 (struct simple_object_xcoff_read *) sobj->data;
700 int u64 = ocr->magic == U64_TOCMAGIC;
701 unsigned int nscns, secnum;
702 simple_object_write_section *section;
703 off_t scnhdr_offset;
704 size_t symtab_offset;
705 off_t secsym_offset;
706 unsigned int nsyms;
707 size_t offset;
708 size_t name_offset;
709 const char *errmsg;
710 unsigned char strsizebuf[4];
711 /* The interface doesn't give us access to the name of the input file
712 yet. We want to use its basename for the FILE symbol. This is
713 what 'gas' uses when told to assemble from stdin. */
714 const char *source_filename = "fake";
715 size_t sflen;
716 union
717 {
718 struct external_syment sym;
719 union external_auxent aux;
720 } syms[2];
721 void (*set_16) (unsigned char *, unsigned short);
722 void (*set_32) (unsigned char *, unsigned int);
723
724 set_16 = simple_object_set_big_16;
725 set_32 = simple_object_set_big_32;
726
727 nscns = 0;
728 for (section = sobj->sections; section != NULL; section = section->next)
729 ++nscns;
730
731 scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0);
732 offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32);
733 name_offset = 4;
734 for (section = sobj->sections; section != NULL; section = section->next)
735 {
736 size_t mask;
737 size_t new_offset;
738 size_t scnsize;
739 struct simple_object_write_section_buffer *buffer;
740
741 mask = (1U << section->align) - 1;
742 new_offset = offset & mask;
743 new_offset &= ~ mask;
744 while (new_offset > offset)
745 {
746 unsigned char zeroes[16];
747 size_t write;
748
749 memset (zeroes, 0, sizeof zeroes);
750 write = new_offset - offset;
751 if (write > sizeof zeroes)
752 write = sizeof zeroes;
753 if (!simple_object_internal_write (descriptor, offset, zeroes, write,
754 &errmsg, err))
755 return errmsg;
756 }
757
758 scnsize = 0;
759 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
760 {
761 if (!simple_object_internal_write (descriptor, offset + scnsize,
762 ((const unsigned char *)
763 buffer->buffer),
764 buffer->size, &errmsg, err))
765 return errmsg;
766 scnsize += buffer->size;
767 }
768
769 if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name,
770 &name_offset, scnhdr_offset,
771 scnsize, offset, section->align,
772 &errmsg, err))
773 return errmsg;
774
775 scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32;
776 offset += scnsize;
777 }
778
779 /* Symbol table is always half-word aligned. */
780 offset += (offset & 1);
781 /* There is a file symbol and a section symbol per section,
782 and each of these has a single auxiliary symbol following. */
783 nsyms = 2 * (nscns + 1);
784 symtab_offset = offset;
785 /* Advance across space reserved for symbol table to locate
786 start of string table. */
787 offset += nsyms * SYMESZ;
788
789 /* Write out file symbol. */
790 memset (&syms[0], 0, sizeof (syms));
791 if (!u64)
792 strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file");
793 set_16 (&syms[0].sym.n_scnum[0], N_DEBUG);
794 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
795 syms[0].sym.n_sclass[0] = C_FILE;
796 syms[0].sym.n_numaux[0] = 1;
797 /* The name need not be nul-terminated if it fits into the x_fname field
798 directly, but must be if it has to be placed into the string table. */
799 sflen = strlen (source_filename);
800 if (sflen <= FILNMLEN)
801 memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
802 else
803 {
804 set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset);
805 if (!simple_object_internal_write (descriptor, offset + name_offset,
806 ((const unsigned char *)
807 source_filename),
808 sflen + 1, &errmsg, err))
809 return errmsg;
810 name_offset += strlen (source_filename) + 1;
811 }
812 if (!simple_object_internal_write (descriptor, symtab_offset,
813 (const unsigned char *) &syms[0],
814 sizeof (syms), &errmsg, err))
815 return errmsg;
816
817 /* Write the string table length, followed by the strings and section
818 symbols in step with each other. */
819 set_32 (strsizebuf, name_offset);
820 if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
821 &errmsg, err))
822 return errmsg;
823
824 name_offset = 4;
825 secsym_offset = symtab_offset + sizeof (syms);
826 memset (&syms[0], 0, sizeof (syms));
827 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
828 syms[0].sym.n_sclass[0] = C_STAT;
829 syms[0].sym.n_numaux[0] = 1;
830 secnum = 1;
831
832 for (section = sobj->sections; section != NULL; section = section->next)
833 {
834 size_t namelen;
835 size_t scnsize;
836 struct simple_object_write_section_buffer *buffer;
837
838 namelen = strlen (section->name);
839 set_16 (&syms[0].sym.n_scnum[0], secnum++);
840 scnsize = 0;
841 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
842 scnsize += buffer->size;
843 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
844 if (namelen > SCNNMLEN)
845 {
846 set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0);
847 set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset);
848 if (!simple_object_internal_write (descriptor, offset + name_offset,
849 ((const unsigned char *)
850 section->name),
851 namelen + 1, &errmsg, err))
852 return errmsg;
853 name_offset += namelen + 1;
854 }
855 else
856 {
857 memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name,
858 strlen (section->name));
859 memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0,
860 N_SYMNMLEN - strlen (section->name));
861 }
862
863 if (!simple_object_internal_write (descriptor, secsym_offset,
864 (const unsigned char *) &syms[0],
865 sizeof (syms), &errmsg, err))
866 return errmsg;
867 secsym_offset += sizeof (syms);
868 }
869
870 if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns,
871 symtab_offset, nsyms, &errmsg, err))
872 return errmsg;
873
874 return NULL;
875 }
876
877 /* Release the private data for an simple_object_write structure. */
878
879 static void
simple_object_xcoff_release_write(void * data)880 simple_object_xcoff_release_write (void *data)
881 {
882 XDELETE (data);
883 }
884
885 /* The XCOFF functions. */
886
887 const struct simple_object_functions simple_object_xcoff_functions =
888 {
889 simple_object_xcoff_match,
890 simple_object_xcoff_find_sections,
891 simple_object_xcoff_fetch_attributes,
892 simple_object_xcoff_release_read,
893 simple_object_xcoff_attributes_merge,
894 simple_object_xcoff_release_attributes,
895 simple_object_xcoff_start_write,
896 simple_object_xcoff_write_to_file,
897 simple_object_xcoff_release_write
898 };
899