RISC-V: Eliminate spurious error w/ reloc truncated message
[deliverable/binutils-gdb.git] / libiberty / simple-object-xcoff.c
1 /* simple-object-coff.c -- routines to manipulate XCOFF object files.
2 Copyright (C) 2013-2018 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_EXT (2)
259 #define C_STAT (3)
260 #define C_FILE (103)
261 #define C_HIDEXT (107)
262
263 #define XTY_SD (1) /* section definition */
264
265 #define XMC_XO (7) /* extended operation */
266
267 /* Private data for an simple_object_read. */
268
269 struct simple_object_xcoff_read
270 {
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;
283 };
284
285 /* Private data for an simple_object_attributes. */
286
287 struct simple_object_xcoff_attributes
288 {
289 /* Magic number. */
290 unsigned short magic;
291 /* Flags. */
292 unsigned short flags;
293 };
294
295 /* See if we have a XCOFF file. */
296
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)
302 {
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;
310
311 magic = simple_object_fetch_big_16 (header);
312
313 if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC)
314 {
315 *errmsg = NULL;
316 *err = 0;
317 return NULL;
318 }
319
320 fetch_16 = simple_object_fetch_big_16;
321 fetch_32 = simple_object_fetch_big_32;
322 fetch_64 = simple_object_fetch_big_64;
323
324 if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
325 errmsg, err))
326 return NULL;
327
328 u64 = magic == U64_TOCMAGIC;
329
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)
334 {
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)));
343
344 }
345 else
346 {
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)));
355
356 }
357
358 return (void *) ocr;
359 }
360
361 /* Read the string table in a XCOFF file. */
362
363 static char *
364 simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
365 const char **errmsg, int *err)
366 {
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;
373
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))
384 {
385 XDELETEVEC (strtab);
386 return NULL;
387 }
388 *strtab_size = strsize;
389 return strtab;
390 }
391
392 /* Find all sections in a XCOFF file. */
393
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)
400 {
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;
415
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))
422 {
423 XDELETEVEC (scnbuf);
424 return errmsg;
425 }
426
427 fetch_16 = simple_object_fetch_big_16;
428 fetch_32 = simple_object_fetch_big_32;
429 fetch_64 = simple_object_fetch_big_64;
430
431 nscns = ocr->nscns;
432 strtab = NULL;
433 strtab_size = 0;
434 for (i = 0; i < nscns; ++i)
435 {
436 unsigned char *scnhdr;
437 unsigned char *scnname;
438 char namebuf[SCNNMLEN + 1];
439 char *name;
440 off_t scnptr;
441 off_t size;
442
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] == '/')
449 {
450 size_t strindex;
451 char *end;
452
453 strindex = strtol (namebuf + 1, &end, 10);
454 if (*end == '\0')
455 {
456 /* The real section name is found in the string
457 table. */
458 if (strtab == NULL)
459 {
460 strtab = simple_object_xcoff_read_strtab (sobj,
461 &strtab_size,
462 &errmsg, err);
463 if (strtab == NULL)
464 {
465 XDELETEVEC (scnbuf);
466 return errmsg;
467 }
468 }
469
470 if (strindex < 4 || strindex >= strtab_size)
471 {
472 XDELETEVEC (strtab);
473 XDELETEVEC (scnbuf);
474 *err = 0;
475 return "section string index out of range";
476 }
477
478 name = strtab + strindex;
479 }
480 }
481
482 if (u64)
483 {
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));
488 }
489 else
490 {
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));
495 }
496
497 if (!(*pfn) (data, name, scnptr, size))
498 break;
499 }
500
501 /* Special handling for .go_export csect. */
502 if (ocr->nsyms > 0)
503 {
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;
509
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))
517 {
518 XDELETEVEC (symtab);
519 XDELETEVEC (scnbuf);
520 return NULL;
521 }
522
523 /* Search in symbol table if we have a ".go_export" symbol. */
524 for (i = 0; i < ocr->nsyms; i += n_numaux + 1)
525 {
526 sym = (unsigned char *) &symtab[i];
527 n_numaux = symtab[i].n_numaux[0];
528
529 if (symtab[i].n_sclass[0] != C_EXT
530 && symtab[i].n_sclass[0] != C_HIDEXT)
531 continue;
532
533 /* Must have at least one csect auxiliary entry. */
534 if (n_numaux < 1 || i + n_numaux >= ocr->nsyms)
535 continue;
536
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;
541
542 if (u64)
543 {
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));
548 }
549 else
550 {
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;
556
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));
561 }
562
563 /* The real symbol name is found in the string table. */
564 if (strtab == NULL)
565 {
566 strtab = simple_object_xcoff_read_strtab (sobj,
567 &strtab_size,
568 &errmsg, err);
569 if (strtab == NULL)
570 {
571 XDELETEVEC (symtab);
572 XDELETEVEC (scnbuf);
573 return errmsg;
574 }
575 }
576
577 if (n_offset >= strtab_size)
578 {
579 XDELETEVEC (strtab);
580 XDELETEVEC (symtab);
581 XDELETEVEC (scnbuf);
582 *err = 0;
583 return "symbol string index out of range";
584 }
585 n_name = strtab + n_offset;
586
587 if (!strcmp (n_name, ".go_export"))
588 {
589 union external_auxent *auxent;
590 unsigned char *aux, *scnhdr;
591 off_t scnptr, x_scnlen;
592
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)
598 {
599 /* Use an intermediate 64-bit type to avoid
600 compilation warning about 32-bit shift below on
601 hosts with 32-bit off_t which aren't supported by
602 AC_SYS_LARGEFILE. */
603 ulong_type x_scnlen64;
604
605 if ((auxent->u.xcoff64.x_csect.x_smtyp & 0x7) != XTY_SD
606 || auxent->u.xcoff64.x_csect.x_smclas != XMC_XO)
607 continue;
608
609 x_scnlen64 = fetch_32 (aux + offsetof (union external_auxent,
610 u.xcoff64.x_csect.x_scnlen_hi));
611 x_scnlen = x_scnlen64 << 32
612 | fetch_32 (aux + offsetof (union external_auxent,
613 u.xcoff64.x_csect.x_scnlen_lo));
614 }
615 else
616 {
617 if ((auxent->u.xcoff32.x_csect.x_smtyp & 0x7) != XTY_SD
618 || auxent->u.xcoff32.x_csect.x_smclas != XMC_XO)
619 continue;
620
621 x_scnlen = fetch_32 (aux + offsetof (union external_auxent,
622 u.xcoff32.x_csect.x_scnlen));
623 }
624
625 /* Get header of containing section. */
626 scnhdr = scnbuf + (n_scnum - 1) * scnhdr_size;
627 if (u64)
628 {
629 scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
630 u.xcoff64.s_scnptr));
631 size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
632 u.xcoff64.s_size));
633 }
634 else
635 {
636 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
637 u.xcoff32.s_scnptr));
638 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
639 u.xcoff32.s_size));
640 }
641 if (n_value + x_scnlen > size)
642 break;
643
644 (*pfn) (data, ".go_export", scnptr + n_value, x_scnlen);
645 break;
646 }
647 }
648 }
649
650 if (symtab != NULL)
651 XDELETEVEC (symtab);
652 if (strtab != NULL)
653 XDELETEVEC (strtab);
654 XDELETEVEC (scnbuf);
655
656 return NULL;
657 }
658
659 /* Fetch the attributes for an simple_object_read. */
660
661 static void *
662 simple_object_xcoff_fetch_attributes (simple_object_read *sobj,
663 const char **errmsg ATTRIBUTE_UNUSED,
664 int *err ATTRIBUTE_UNUSED)
665 {
666 struct simple_object_xcoff_read *ocr =
667 (struct simple_object_xcoff_read *) sobj->data;
668 struct simple_object_xcoff_attributes *ret;
669
670 ret = XNEW (struct simple_object_xcoff_attributes);
671 ret->magic = ocr->magic;
672 ret->flags = ocr->flags;
673 return ret;
674 }
675
676 /* Release the private data for an simple_object_read. */
677
678 static void
679 simple_object_xcoff_release_read (void *data)
680 {
681 XDELETE (data);
682 }
683
684 /* Compare two attributes structures. */
685
686 static const char *
687 simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err)
688 {
689 struct simple_object_xcoff_attributes *to =
690 (struct simple_object_xcoff_attributes *) todata;
691 struct simple_object_xcoff_attributes *from =
692 (struct simple_object_xcoff_attributes *) fromdata;
693
694 if (to->magic != from->magic)
695 {
696 *err = 0;
697 return "XCOFF object format mismatch";
698 }
699 return NULL;
700 }
701
702 /* Release the private data for an attributes structure. */
703
704 static void
705 simple_object_xcoff_release_attributes (void *data)
706 {
707 XDELETE (data);
708 }
709
710 /* Prepare to write out a file. */
711
712 static void *
713 simple_object_xcoff_start_write (void *attributes_data,
714 const char **errmsg ATTRIBUTE_UNUSED,
715 int *err ATTRIBUTE_UNUSED)
716 {
717 struct simple_object_xcoff_attributes *attrs =
718 (struct simple_object_xcoff_attributes *) attributes_data;
719 struct simple_object_xcoff_attributes *ret;
720
721 /* We're just going to record the attributes, but we need to make a
722 copy because the user may delete them. */
723 ret = XNEW (struct simple_object_xcoff_attributes);
724 *ret = *attrs;
725 return ret;
726 }
727
728 /* Write out a XCOFF filehdr. */
729
730 static int
731 simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor,
732 unsigned int nscns, size_t symtab_offset,
733 unsigned int nsyms, const char **errmsg,
734 int *err)
735 {
736 struct simple_object_xcoff_attributes *attrs =
737 (struct simple_object_xcoff_attributes *) sobj->data;
738 int u64 = attrs->magic == U64_TOCMAGIC;
739 unsigned char hdrbuf[sizeof (struct external_filehdr)];
740 unsigned char *hdr;
741 void (*set_16) (unsigned char *, unsigned short);
742 void (*set_32) (unsigned char *, unsigned int);
743 void (*set_64) (unsigned char *, ulong_type);
744
745 hdr = &hdrbuf[0];
746
747 set_16 = simple_object_set_big_16;
748 set_32 = simple_object_set_big_32;
749 set_64 = simple_object_set_big_64;
750
751 memset (hdr, 0, sizeof (struct external_filehdr));
752
753 set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
754 set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
755 /* f_timdat left as zero. */
756 if (u64)
757 {
758 set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
759 symtab_offset);
760 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
761 nsyms);
762 /* f_opthdr left as zero. */
763 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
764 attrs->flags);
765 }
766 else
767 {
768 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
769 symtab_offset);
770 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
771 nsyms);
772 /* f_opthdr left as zero. */
773 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
774 attrs->flags);
775 }
776
777 return simple_object_internal_write (descriptor, 0, hdrbuf,
778 sizeof (struct external_filehdr),
779 errmsg, err);
780 }
781
782 /* Write out a XCOFF section header. */
783
784 static int
785 simple_object_xcoff_write_scnhdr (simple_object_write *sobj,
786 int descriptor,
787 const char *name, size_t *name_offset,
788 off_t scnhdr_offset, size_t scnsize,
789 off_t offset, unsigned int align,
790 const char **errmsg, int *err)
791 {
792 struct simple_object_xcoff_read *ocr =
793 (struct simple_object_xcoff_read *) sobj->data;
794 int u64 = ocr->magic == U64_TOCMAGIC;
795 void (*set_32) (unsigned char *, unsigned int);
796 void (*set_64) (unsigned char *, unsigned int);
797 unsigned char hdrbuf[sizeof (struct external_scnhdr)];
798 unsigned char *hdr;
799 size_t namelen;
800 unsigned int flags;
801
802 set_32 = simple_object_set_big_32;
803 set_64 = simple_object_set_big_32;
804
805 memset (hdrbuf, 0, sizeof hdrbuf);
806 hdr = &hdrbuf[0];
807
808 namelen = strlen (name);
809 if (namelen <= SCNNMLEN)
810 strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name),
811 name, SCNNMLEN);
812 else
813 {
814 snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
815 SCNNMLEN, "/%lu", (unsigned long) *name_offset);
816 *name_offset += namelen + 1;
817 }
818
819 /* s_paddr left as zero. */
820 /* s_vaddr left as zero. */
821 if (u64)
822 {
823 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size),
824 scnsize);
825 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr),
826 offset);
827 }
828 else
829 {
830 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size),
831 scnsize);
832 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr),
833 offset);
834 }
835 /* s_relptr left as zero. */
836 /* s_lnnoptr left as zero. */
837 /* s_nreloc left as zero. */
838 /* s_nlnno left as zero. */
839 flags = STYP_DATA;
840 if (align > 13)
841 align = 13;
842 if (u64)
843 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags);
844 else
845 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags);
846
847 return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
848 u64 ? SCNHSZ64 : SCNHSZ32,
849 errmsg, err);
850 }
851
852 /* Write out a complete XCOFF file. */
853
854 static const char *
855 simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor,
856 int *err)
857 {
858 struct simple_object_xcoff_read *ocr =
859 (struct simple_object_xcoff_read *) sobj->data;
860 int u64 = ocr->magic == U64_TOCMAGIC;
861 unsigned int nscns, secnum;
862 simple_object_write_section *section;
863 off_t scnhdr_offset;
864 size_t symtab_offset;
865 off_t secsym_offset;
866 unsigned int nsyms;
867 size_t offset;
868 size_t name_offset;
869 const char *errmsg;
870 unsigned char strsizebuf[4];
871 /* The interface doesn't give us access to the name of the input file
872 yet. We want to use its basename for the FILE symbol. This is
873 what 'gas' uses when told to assemble from stdin. */
874 const char *source_filename = "fake";
875 size_t sflen;
876 union
877 {
878 struct external_syment sym;
879 union external_auxent aux;
880 } syms[2];
881 void (*set_16) (unsigned char *, unsigned short);
882 void (*set_32) (unsigned char *, unsigned int);
883
884 set_16 = simple_object_set_big_16;
885 set_32 = simple_object_set_big_32;
886
887 nscns = 0;
888 for (section = sobj->sections; section != NULL; section = section->next)
889 ++nscns;
890
891 scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0);
892 offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32);
893 name_offset = 4;
894 for (section = sobj->sections; section != NULL; section = section->next)
895 {
896 size_t mask;
897 size_t new_offset;
898 size_t scnsize;
899 struct simple_object_write_section_buffer *buffer;
900
901 mask = (1U << section->align) - 1;
902 new_offset = offset & mask;
903 new_offset &= ~ mask;
904 while (new_offset > offset)
905 {
906 unsigned char zeroes[16];
907 size_t write;
908
909 memset (zeroes, 0, sizeof zeroes);
910 write = new_offset - offset;
911 if (write > sizeof zeroes)
912 write = sizeof zeroes;
913 if (!simple_object_internal_write (descriptor, offset, zeroes, write,
914 &errmsg, err))
915 return errmsg;
916 }
917
918 scnsize = 0;
919 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
920 {
921 if (!simple_object_internal_write (descriptor, offset + scnsize,
922 ((const unsigned char *)
923 buffer->buffer),
924 buffer->size, &errmsg, err))
925 return errmsg;
926 scnsize += buffer->size;
927 }
928
929 if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name,
930 &name_offset, scnhdr_offset,
931 scnsize, offset, section->align,
932 &errmsg, err))
933 return errmsg;
934
935 scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32;
936 offset += scnsize;
937 }
938
939 /* Symbol table is always half-word aligned. */
940 offset += (offset & 1);
941 /* There is a file symbol and a section symbol per section,
942 and each of these has a single auxiliary symbol following. */
943 nsyms = 2 * (nscns + 1);
944 symtab_offset = offset;
945 /* Advance across space reserved for symbol table to locate
946 start of string table. */
947 offset += nsyms * SYMESZ;
948
949 /* Write out file symbol. */
950 memset (&syms[0], 0, sizeof (syms));
951 if (!u64)
952 strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file");
953 set_16 (&syms[0].sym.n_scnum[0], N_DEBUG);
954 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
955 syms[0].sym.n_sclass[0] = C_FILE;
956 syms[0].sym.n_numaux[0] = 1;
957 /* The name need not be nul-terminated if it fits into the x_fname field
958 directly, but must be if it has to be placed into the string table. */
959 sflen = strlen (source_filename);
960 if (sflen <= FILNMLEN)
961 memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
962 else
963 {
964 set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset);
965 if (!simple_object_internal_write (descriptor, offset + name_offset,
966 ((const unsigned char *)
967 source_filename),
968 sflen + 1, &errmsg, err))
969 return errmsg;
970 name_offset += strlen (source_filename) + 1;
971 }
972 if (!simple_object_internal_write (descriptor, symtab_offset,
973 (const unsigned char *) &syms[0],
974 sizeof (syms), &errmsg, err))
975 return errmsg;
976
977 /* Write the string table length, followed by the strings and section
978 symbols in step with each other. */
979 set_32 (strsizebuf, name_offset);
980 if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
981 &errmsg, err))
982 return errmsg;
983
984 name_offset = 4;
985 secsym_offset = symtab_offset + sizeof (syms);
986 memset (&syms[0], 0, sizeof (syms));
987 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
988 syms[0].sym.n_sclass[0] = C_STAT;
989 syms[0].sym.n_numaux[0] = 1;
990 secnum = 1;
991
992 for (section = sobj->sections; section != NULL; section = section->next)
993 {
994 size_t namelen;
995 size_t scnsize;
996 struct simple_object_write_section_buffer *buffer;
997
998 namelen = strlen (section->name);
999 set_16 (&syms[0].sym.n_scnum[0], secnum++);
1000 scnsize = 0;
1001 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
1002 scnsize += buffer->size;
1003 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
1004 if (namelen > SCNNMLEN)
1005 {
1006 set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0);
1007 set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset);
1008 if (!simple_object_internal_write (descriptor, offset + name_offset,
1009 ((const unsigned char *)
1010 section->name),
1011 namelen + 1, &errmsg, err))
1012 return errmsg;
1013 name_offset += namelen + 1;
1014 }
1015 else
1016 {
1017 memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name,
1018 strlen (section->name));
1019 memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0,
1020 N_SYMNMLEN - strlen (section->name));
1021 }
1022
1023 if (!simple_object_internal_write (descriptor, secsym_offset,
1024 (const unsigned char *) &syms[0],
1025 sizeof (syms), &errmsg, err))
1026 return errmsg;
1027 secsym_offset += sizeof (syms);
1028 }
1029
1030 if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns,
1031 symtab_offset, nsyms, &errmsg, err))
1032 return errmsg;
1033
1034 return NULL;
1035 }
1036
1037 /* Release the private data for an simple_object_write structure. */
1038
1039 static void
1040 simple_object_xcoff_release_write (void *data)
1041 {
1042 XDELETE (data);
1043 }
1044
1045 /* The XCOFF functions. */
1046
1047 const struct simple_object_functions simple_object_xcoff_functions =
1048 {
1049 simple_object_xcoff_match,
1050 simple_object_xcoff_find_sections,
1051 simple_object_xcoff_fetch_attributes,
1052 simple_object_xcoff_release_read,
1053 simple_object_xcoff_attributes_merge,
1054 simple_object_xcoff_release_attributes,
1055 simple_object_xcoff_start_write,
1056 simple_object_xcoff_write_to_file,
1057 simple_object_xcoff_release_write,
1058 NULL
1059 };
This page took 0.063836 seconds and 4 git commands to generate.