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 = 610 fetch_32 (aux + offsetof (union external_auxent, 611 u.xcoff64.x_csect.x_scnlen_hi)); 612 x_scnlen = 613 ((x_scnlen64 << 32) 614 | fetch_32 (aux 615 + offsetof (union external_auxent, 616 u.xcoff64.x_csect.x_scnlen_lo))); 617 } 618 else 619 { 620 if ((auxent->u.xcoff32.x_csect.x_smtyp & 0x7) != XTY_SD 621 || auxent->u.xcoff32.x_csect.x_smclas != XMC_XO) 622 continue; 623 624 x_scnlen = fetch_32 (aux + offsetof (union external_auxent, 625 u.xcoff32.x_csect.x_scnlen)); 626 } 627 628 /* Get header of containing section. */ 629 scnhdr = scnbuf + (n_scnum - 1) * scnhdr_size; 630 if (u64) 631 { 632 scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr, 633 u.xcoff64.s_scnptr)); 634 size = fetch_64 (scnhdr + offsetof (struct external_scnhdr, 635 u.xcoff64.s_size)); 636 } 637 else 638 { 639 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, 640 u.xcoff32.s_scnptr)); 641 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, 642 u.xcoff32.s_size)); 643 } 644 if (n_value + x_scnlen > size) 645 break; 646 647 (*pfn) (data, ".go_export", scnptr + n_value, x_scnlen); 648 break; 649 } 650 } 651 } 652 653 if (symtab != NULL) 654 XDELETEVEC (symtab); 655 if (strtab != NULL) 656 XDELETEVEC (strtab); 657 XDELETEVEC (scnbuf); 658 659 return NULL; 660 } 661 662 /* Fetch the attributes for an simple_object_read. */ 663 664 static void * 665 simple_object_xcoff_fetch_attributes (simple_object_read *sobj, 666 const char **errmsg ATTRIBUTE_UNUSED, 667 int *err ATTRIBUTE_UNUSED) 668 { 669 struct simple_object_xcoff_read *ocr = 670 (struct simple_object_xcoff_read *) sobj->data; 671 struct simple_object_xcoff_attributes *ret; 672 673 ret = XNEW (struct simple_object_xcoff_attributes); 674 ret->magic = ocr->magic; 675 ret->flags = ocr->flags; 676 return ret; 677 } 678 679 /* Release the private data for an simple_object_read. */ 680 681 static void 682 simple_object_xcoff_release_read (void *data) 683 { 684 XDELETE (data); 685 } 686 687 /* Compare two attributes structures. */ 688 689 static const char * 690 simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err) 691 { 692 struct simple_object_xcoff_attributes *to = 693 (struct simple_object_xcoff_attributes *) todata; 694 struct simple_object_xcoff_attributes *from = 695 (struct simple_object_xcoff_attributes *) fromdata; 696 697 if (to->magic != from->magic) 698 { 699 *err = 0; 700 return "XCOFF object format mismatch"; 701 } 702 return NULL; 703 } 704 705 /* Release the private data for an attributes structure. */ 706 707 static void 708 simple_object_xcoff_release_attributes (void *data) 709 { 710 XDELETE (data); 711 } 712 713 /* Prepare to write out a file. */ 714 715 static void * 716 simple_object_xcoff_start_write (void *attributes_data, 717 const char **errmsg ATTRIBUTE_UNUSED, 718 int *err ATTRIBUTE_UNUSED) 719 { 720 struct simple_object_xcoff_attributes *attrs = 721 (struct simple_object_xcoff_attributes *) attributes_data; 722 struct simple_object_xcoff_attributes *ret; 723 724 /* We're just going to record the attributes, but we need to make a 725 copy because the user may delete them. */ 726 ret = XNEW (struct simple_object_xcoff_attributes); 727 *ret = *attrs; 728 return ret; 729 } 730 731 /* Write out a XCOFF filehdr. */ 732 733 static int 734 simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor, 735 unsigned int nscns, size_t symtab_offset, 736 unsigned int nsyms, const char **errmsg, 737 int *err) 738 { 739 struct simple_object_xcoff_attributes *attrs = 740 (struct simple_object_xcoff_attributes *) sobj->data; 741 int u64 = attrs->magic == U64_TOCMAGIC; 742 unsigned char hdrbuf[sizeof (struct external_filehdr)]; 743 unsigned char *hdr; 744 void (*set_16) (unsigned char *, unsigned short); 745 void (*set_32) (unsigned char *, unsigned int); 746 void (*set_64) (unsigned char *, ulong_type); 747 748 hdr = &hdrbuf[0]; 749 750 set_16 = simple_object_set_big_16; 751 set_32 = simple_object_set_big_32; 752 set_64 = simple_object_set_big_64; 753 754 memset (hdr, 0, sizeof (struct external_filehdr)); 755 756 set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic); 757 set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns); 758 /* f_timdat left as zero. */ 759 if (u64) 760 { 761 set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr), 762 symtab_offset); 763 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms), 764 nsyms); 765 /* f_opthdr left as zero. */ 766 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags), 767 attrs->flags); 768 } 769 else 770 { 771 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr), 772 symtab_offset); 773 set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms), 774 nsyms); 775 /* f_opthdr left as zero. */ 776 set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags), 777 attrs->flags); 778 } 779 780 return simple_object_internal_write (descriptor, 0, hdrbuf, 781 sizeof (struct external_filehdr), 782 errmsg, err); 783 } 784 785 /* Write out a XCOFF section header. */ 786 787 static int 788 simple_object_xcoff_write_scnhdr (simple_object_write *sobj, 789 int descriptor, 790 const char *name, size_t *name_offset, 791 off_t scnhdr_offset, size_t scnsize, 792 off_t offset, unsigned int align, 793 const char **errmsg, int *err) 794 { 795 struct simple_object_xcoff_read *ocr = 796 (struct simple_object_xcoff_read *) sobj->data; 797 int u64 = ocr->magic == U64_TOCMAGIC; 798 void (*set_32) (unsigned char *, unsigned int); 799 void (*set_64) (unsigned char *, unsigned int); 800 unsigned char hdrbuf[sizeof (struct external_scnhdr)]; 801 unsigned char *hdr; 802 size_t namelen; 803 unsigned int flags; 804 805 set_32 = simple_object_set_big_32; 806 set_64 = simple_object_set_big_32; 807 808 memset (hdrbuf, 0, sizeof hdrbuf); 809 hdr = &hdrbuf[0]; 810 811 namelen = strlen (name); 812 if (namelen <= SCNNMLEN) 813 strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), 814 name, SCNNMLEN); 815 else 816 { 817 snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name), 818 SCNNMLEN, "/%lu", (unsigned long) *name_offset); 819 *name_offset += namelen + 1; 820 } 821 822 /* s_paddr left as zero. */ 823 /* s_vaddr left as zero. */ 824 if (u64) 825 { 826 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size), 827 scnsize); 828 set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr), 829 offset); 830 } 831 else 832 { 833 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size), 834 scnsize); 835 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr), 836 offset); 837 } 838 /* s_relptr left as zero. */ 839 /* s_lnnoptr left as zero. */ 840 /* s_nreloc left as zero. */ 841 /* s_nlnno left as zero. */ 842 flags = STYP_DATA; 843 if (align > 13) 844 align = 13; 845 if (u64) 846 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags); 847 else 848 set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags); 849 850 return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf, 851 u64 ? SCNHSZ64 : SCNHSZ32, 852 errmsg, err); 853 } 854 855 /* Write out a complete XCOFF file. */ 856 857 static const char * 858 simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor, 859 int *err) 860 { 861 struct simple_object_xcoff_read *ocr = 862 (struct simple_object_xcoff_read *) sobj->data; 863 int u64 = ocr->magic == U64_TOCMAGIC; 864 unsigned int nscns, secnum; 865 simple_object_write_section *section; 866 off_t scnhdr_offset; 867 size_t symtab_offset; 868 off_t secsym_offset; 869 unsigned int nsyms; 870 size_t offset; 871 size_t name_offset; 872 const char *errmsg; 873 unsigned char strsizebuf[4]; 874 /* The interface doesn't give us access to the name of the input file 875 yet. We want to use its basename for the FILE symbol. This is 876 what 'gas' uses when told to assemble from stdin. */ 877 const char *source_filename = "fake"; 878 size_t sflen; 879 union 880 { 881 struct external_syment sym; 882 union external_auxent aux; 883 } syms[2]; 884 void (*set_16) (unsigned char *, unsigned short); 885 void (*set_32) (unsigned char *, unsigned int); 886 887 set_16 = simple_object_set_big_16; 888 set_32 = simple_object_set_big_32; 889 890 nscns = 0; 891 for (section = sobj->sections; section != NULL; section = section->next) 892 ++nscns; 893 894 scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0); 895 offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32); 896 name_offset = 4; 897 for (section = sobj->sections; section != NULL; section = section->next) 898 { 899 size_t mask; 900 size_t new_offset; 901 size_t scnsize; 902 struct simple_object_write_section_buffer *buffer; 903 904 mask = (1U << section->align) - 1; 905 new_offset = offset & mask; 906 new_offset &= ~ mask; 907 while (new_offset > offset) 908 { 909 unsigned char zeroes[16]; 910 size_t write; 911 912 memset (zeroes, 0, sizeof zeroes); 913 write = new_offset - offset; 914 if (write > sizeof zeroes) 915 write = sizeof zeroes; 916 if (!simple_object_internal_write (descriptor, offset, zeroes, write, 917 &errmsg, err)) 918 return errmsg; 919 } 920 921 scnsize = 0; 922 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 923 { 924 if (!simple_object_internal_write (descriptor, offset + scnsize, 925 ((const unsigned char *) 926 buffer->buffer), 927 buffer->size, &errmsg, err)) 928 return errmsg; 929 scnsize += buffer->size; 930 } 931 932 if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name, 933 &name_offset, scnhdr_offset, 934 scnsize, offset, section->align, 935 &errmsg, err)) 936 return errmsg; 937 938 scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32; 939 offset += scnsize; 940 } 941 942 /* Symbol table is always half-word aligned. */ 943 offset += (offset & 1); 944 /* There is a file symbol and a section symbol per section, 945 and each of these has a single auxiliary symbol following. */ 946 nsyms = 2 * (nscns + 1); 947 symtab_offset = offset; 948 /* Advance across space reserved for symbol table to locate 949 start of string table. */ 950 offset += nsyms * SYMESZ; 951 952 /* Write out file symbol. */ 953 memset (&syms[0], 0, sizeof (syms)); 954 if (!u64) 955 strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file"); 956 set_16 (&syms[0].sym.n_scnum[0], N_DEBUG); 957 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE); 958 syms[0].sym.n_sclass[0] = C_FILE; 959 syms[0].sym.n_numaux[0] = 1; 960 /* The name need not be nul-terminated if it fits into the x_fname field 961 directly, but must be if it has to be placed into the string table. */ 962 sflen = strlen (source_filename); 963 if (sflen <= FILNMLEN) 964 memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); 965 else 966 { 967 set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset); 968 if (!simple_object_internal_write (descriptor, offset + name_offset, 969 ((const unsigned char *) 970 source_filename), 971 sflen + 1, &errmsg, err)) 972 return errmsg; 973 name_offset += strlen (source_filename) + 1; 974 } 975 if (!simple_object_internal_write (descriptor, symtab_offset, 976 (const unsigned char *) &syms[0], 977 sizeof (syms), &errmsg, err)) 978 return errmsg; 979 980 /* Write the string table length, followed by the strings and section 981 symbols in step with each other. */ 982 set_32 (strsizebuf, name_offset); 983 if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, 984 &errmsg, err)) 985 return errmsg; 986 987 name_offset = 4; 988 secsym_offset = symtab_offset + sizeof (syms); 989 memset (&syms[0], 0, sizeof (syms)); 990 set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE); 991 syms[0].sym.n_sclass[0] = C_STAT; 992 syms[0].sym.n_numaux[0] = 1; 993 secnum = 1; 994 995 for (section = sobj->sections; section != NULL; section = section->next) 996 { 997 size_t namelen; 998 size_t scnsize; 999 struct simple_object_write_section_buffer *buffer; 1000 1001 namelen = strlen (section->name); 1002 set_16 (&syms[0].sym.n_scnum[0], secnum++); 1003 scnsize = 0; 1004 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 1005 scnsize += buffer->size; 1006 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); 1007 if (namelen > SCNNMLEN) 1008 { 1009 set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0); 1010 set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset); 1011 if (!simple_object_internal_write (descriptor, offset + name_offset, 1012 ((const unsigned char *) 1013 section->name), 1014 namelen + 1, &errmsg, err)) 1015 return errmsg; 1016 name_offset += namelen + 1; 1017 } 1018 else 1019 { 1020 memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name, 1021 strlen (section->name)); 1022 memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0, 1023 N_SYMNMLEN - strlen (section->name)); 1024 } 1025 1026 if (!simple_object_internal_write (descriptor, secsym_offset, 1027 (const unsigned char *) &syms[0], 1028 sizeof (syms), &errmsg, err)) 1029 return errmsg; 1030 secsym_offset += sizeof (syms); 1031 } 1032 1033 if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns, 1034 symtab_offset, nsyms, &errmsg, err)) 1035 return errmsg; 1036 1037 return NULL; 1038 } 1039 1040 /* Release the private data for an simple_object_write structure. */ 1041 1042 static void 1043 simple_object_xcoff_release_write (void *data) 1044 { 1045 XDELETE (data); 1046 } 1047 1048 /* The XCOFF functions. */ 1049 1050 const struct simple_object_functions simple_object_xcoff_functions = 1051 { 1052 simple_object_xcoff_match, 1053 simple_object_xcoff_find_sections, 1054 simple_object_xcoff_fetch_attributes, 1055 simple_object_xcoff_release_read, 1056 simple_object_xcoff_attributes_merge, 1057 simple_object_xcoff_release_attributes, 1058 simple_object_xcoff_start_write, 1059 simple_object_xcoff_write_to_file, 1060 simple_object_xcoff_release_write, 1061 NULL 1062 }; 1063