1 /* simple-object-coff.c -- routines to manipulate COFF object files. 2 Copyright (C) 2010-2026 Free Software Foundation, Inc. 3 Written by Ian Lance Taylor, Google. 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 /* COFF structures and constants. */ 46 47 /* COFF 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 unsigned char f_symptr[4]; /* file pointer to symtab */ 55 unsigned char f_nsyms[4]; /* number of symtab entries */ 56 unsigned char f_opthdr[2]; /* sizeof(optional hdr) */ 57 unsigned char f_flags[2]; /* flags */ 58 }; 59 60 /* BigObj COFF file header. */ 61 62 struct external_filehdr_bigobj 63 { 64 unsigned char sig1[2]; /* Must be 0x0000 */ 65 unsigned char sig2[2]; /* Must be 0xFFFF */ 66 unsigned char version[2]; /* Version, currently 2 */ 67 unsigned char machine[2]; /* Machine type */ 68 unsigned char timdat[4]; /* time & date stamp */ 69 unsigned char classid[16]; /* Magic GUID that identifies BigObj format */ 70 unsigned char sizeofdata[4]; /* Size of data (unused, set to 0) */ 71 unsigned char flags[4]; /* Flags (unused, set to 0) */ 72 unsigned char metadatasize[4]; /* Metadata size (unused, set to 0) */ 73 unsigned char metadataoffset[4]; /* Metadata offset (unused, set to 0) */ 74 unsigned char nscns[4]; /* number of sections (32-bit!) */ 75 unsigned char symptr[4]; /* file pointer to symtab */ 76 unsigned char nsyms[4]; /* number of symtab entries */ 77 }; 78 79 /* The BigObj magic GUID (ClassID). */ 80 static const unsigned char bigobj_magic[16] = 81 { 82 0xC7, 0xA1, 0xBA, 0xD1, 0xEE, 0xBA, 0xA9, 0x4B, 83 0xAF, 0x20, 0xFA, 0xF6, 0x6A, 0xA4, 0xDC, 0xB8 84 }; 85 86 /* Bits for filehdr f_flags field. */ 87 88 #define F_EXEC (0x0002) 89 #define IMAGE_FILE_SYSTEM (0x1000) 90 #define IMAGE_FILE_DLL (0x2000) 91 92 /* COFF section header. */ 93 94 struct external_scnhdr 95 { 96 unsigned char s_name[8]; /* section name */ 97 unsigned char s_paddr[4]; /* physical address, aliased s_nlib */ 98 unsigned char s_vaddr[4]; /* virtual address */ 99 unsigned char s_size[4]; /* section size */ 100 unsigned char s_scnptr[4]; /* file ptr to raw data for section */ 101 unsigned char s_relptr[4]; /* file ptr to relocation */ 102 unsigned char s_lnnoptr[4]; /* file ptr to line numbers */ 103 unsigned char s_nreloc[2]; /* number of relocation entries */ 104 unsigned char s_nlnno[2]; /* number of line number entries */ 105 unsigned char s_flags[4]; /* flags */ 106 }; 107 108 /* The length of the s_name field in struct external_scnhdr. */ 109 110 #define SCNNMLEN (8) 111 112 /* Bits for scnhdr s_flags field. This includes some bits defined 113 only for PE. This may need to be moved into coff_magic. */ 114 115 #define STYP_DATA (1 << 6) 116 #define IMAGE_SCN_MEM_DISCARDABLE (1 << 25) 117 #define IMAGE_SCN_MEM_SHARED (1 << 28) 118 #define IMAGE_SCN_MEM_READ (1 << 30) 119 120 #define IMAGE_SCN_ALIGN_POWER_BIT_POS 20 121 #define IMAGE_SCN_ALIGN_POWER_CONST(val) \ 122 (((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS) 123 124 /* COFF symbol table entry. */ 125 126 #define E_SYMNMLEN 8 /* # characters in a symbol name */ 127 128 struct external_syment 129 { 130 union 131 { 132 unsigned char e_name[E_SYMNMLEN]; 133 134 struct 135 { 136 unsigned char e_zeroes[4]; 137 unsigned char e_offset[4]; 138 } e; 139 } e; 140 141 unsigned char e_value[4]; 142 unsigned char e_scnum[2]; 143 unsigned char e_type[2]; 144 unsigned char e_sclass[1]; 145 unsigned char e_numaux[1]; 146 }; 147 148 /* BigObj COFF symbol table entry (20 bytes instead of 18). */ 149 150 struct external_syment_bigobj 151 { 152 union 153 { 154 unsigned char e_name[E_SYMNMLEN]; 155 156 struct 157 { 158 unsigned char e_zeroes[4]; 159 unsigned char e_offset[4]; 160 } e; 161 } e; 162 163 unsigned char e_value[4]; 164 unsigned char e_scnum[4]; /* 32-bit section number! */ 165 unsigned char e_type[2]; 166 unsigned char e_sclass[1]; 167 unsigned char e_numaux[1]; 168 }; 169 170 /* Length allowed for filename in aux sym format 4. */ 171 172 #define E_FILNMLEN 18 173 174 /* Omits x_sym and other unused variants. */ 175 176 union external_auxent 177 { 178 /* Aux sym format 4: file. */ 179 union 180 { 181 char x_fname[E_FILNMLEN]; 182 struct 183 { 184 unsigned char x_zeroes[4]; 185 unsigned char x_offset[4]; 186 } x_n; 187 } x_file; 188 /* Aux sym format 5: section. */ 189 struct 190 { 191 unsigned char x_scnlen[4]; /* section length */ 192 unsigned char x_nreloc[2]; /* # relocation entries */ 193 unsigned char x_nlinno[2]; /* # line numbers */ 194 unsigned char x_checksum[4]; /* section COMDAT checksum */ 195 unsigned char x_associated[2]; /* COMDAT assoc section index */ 196 unsigned char x_comdat[1]; /* COMDAT selection number */ 197 } x_scn; 198 }; 199 200 /* BigObj auxiliary symbol (20 bytes to match symbol size). */ 201 202 union external_auxent_bigobj 203 { 204 /* Aux sym format 4: file. */ 205 union 206 { 207 char x_fname[E_FILNMLEN]; 208 struct 209 { 210 unsigned char x_zeroes[4]; 211 unsigned char x_offset[4]; 212 } x_n; 213 } x_file; 214 /* Aux sym format 5: section. */ 215 struct 216 { 217 unsigned char x_scnlen[4]; /* section length */ 218 unsigned char x_nreloc[2]; /* # relocation entries */ 219 unsigned char x_nlinno[2]; /* # line numbers */ 220 unsigned char x_checksum[4]; /* section COMDAT checksum */ 221 unsigned char x_associated[2]; /* COMDAT assoc section index */ 222 unsigned char x_comdat[1]; /* COMDAT selection number */ 223 unsigned char x_pad[3]; /* Padding to 20 bytes */ 224 } x_scn; 225 }; 226 227 /* Symbol-related constants. */ 228 229 #define IMAGE_SYM_DEBUG (-2) 230 #define IMAGE_SYM_TYPE_NULL (0) 231 #define IMAGE_SYM_DTYPE_NULL (0) 232 #define IMAGE_SYM_CLASS_STATIC (3) 233 #define IMAGE_SYM_CLASS_FILE (103) 234 235 #define IMAGE_SYM_TYPE \ 236 ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL) 237 238 /* Private data for an simple_object_read. */ 239 240 struct simple_object_coff_read 241 { 242 /* Magic number. */ 243 unsigned short magic; 244 /* Whether the file is big-endian. */ 245 unsigned char is_big_endian; 246 /* Whether this is BigObj format. */ 247 unsigned char is_bigobj; 248 /* Number of sections. */ 249 unsigned int nscns; 250 /* File offset of symbol table. */ 251 off_t symptr; 252 /* Number of symbol table entries. */ 253 unsigned int nsyms; 254 /* Flags. */ 255 unsigned short flags; 256 /* Offset of section headers in file. */ 257 off_t scnhdr_offset; 258 }; 259 260 /* Private data for an simple_object_attributes. */ 261 262 struct simple_object_coff_attributes 263 { 264 /* Magic number. */ 265 unsigned short magic; 266 /* Whether the file is big-endian. */ 267 unsigned char is_big_endian; 268 /* Whether this is BigObj format. */ 269 unsigned char is_bigobj; 270 /* Flags. */ 271 unsigned short flags; 272 }; 273 274 /* There is no magic number which indicates a COFF file as opposed to 275 any other sort of file. Instead, each COFF file starts with a 276 two-byte magic number which also indicates the type of the target. 277 This struct holds a magic number as well as characteristics of that 278 COFF format. */ 279 280 struct coff_magic_struct 281 { 282 /* Magic number. */ 283 unsigned short magic; 284 /* Whether this magic number is for a big-endian file. */ 285 unsigned char is_big_endian; 286 /* Flag bits, in the f_flags fields, which indicates that this file 287 is not a relocatable object file. There is no flag which 288 specifically indicates a relocatable object file, it is only 289 implied by the absence of these flags. */ 290 unsigned short non_object_flags; 291 }; 292 293 /* This is a list of the COFF magic numbers which we recognize, namely 294 the ones used on Windows. More can be added as needed. */ 295 296 static const struct coff_magic_struct coff_magic[] = 297 { 298 /* i386. */ 299 { 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }, 300 /* x86_64. */ 301 { 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }, 302 /* AArch64. */ 303 { 0xaa64, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL } 304 }; 305 306 /* See if we have a COFF file. */ 307 308 static void * 309 simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], 310 int descriptor, off_t offset, 311 const char *segment_name ATTRIBUTE_UNUSED, 312 const char **errmsg, int *err) 313 { 314 size_t c; 315 unsigned short magic_big; 316 unsigned short magic_little; 317 unsigned short magic; 318 size_t i; 319 int is_big_endian; 320 unsigned short (*fetch_16) (const unsigned char *); 321 unsigned int (*fetch_32) (const unsigned char *); 322 unsigned char hdrbuf[sizeof (struct external_filehdr_bigobj)]; 323 unsigned short flags; 324 struct simple_object_coff_read *ocr; 325 unsigned short sig1, sig2; 326 327 /* Try regular COFF first. */ 328 c = sizeof (coff_magic) / sizeof (coff_magic[0]); 329 magic_big = simple_object_fetch_big_16 (header); 330 magic_little = simple_object_fetch_little_16 (header); 331 for (i = 0; i < c; ++i) 332 { 333 if (coff_magic[i].is_big_endian 334 ? coff_magic[i].magic == magic_big 335 : coff_magic[i].magic == magic_little) 336 break; 337 } 338 339 /* Check for BigObj if regular COFF didn't match. */ 340 sig1 = simple_object_fetch_little_16 (header); 341 sig2 = simple_object_fetch_little_16 (header + 2); 342 343 if (i >= c && (sig1 != 0 || sig2 != 0xFFFF)) 344 { 345 /* Not regular COFF and not BigObj. */ 346 *errmsg = NULL; 347 *err = 0; 348 return NULL; 349 } 350 351 if (sig1 == 0 && sig2 == 0xFFFF) 352 { 353 /* This looks like BigObj. Verify the ClassID. */ 354 unsigned char bigobj_hdrbuf[sizeof (struct external_filehdr_bigobj)]; 355 356 if (!simple_object_internal_read (descriptor, offset, bigobj_hdrbuf, 357 sizeof bigobj_hdrbuf, errmsg, err)) 358 return NULL; 359 360 if (memcmp (bigobj_hdrbuf + offsetof (struct external_filehdr_bigobj, 361 classid), 362 bigobj_magic, 16) != 0) 363 { 364 *errmsg = NULL; 365 *err = 0; 366 return NULL; 367 } 368 369 /* BigObj is always little-endian. */ 370 is_big_endian = 0; 371 372 ocr = XNEW (struct simple_object_coff_read); 373 ocr->magic = simple_object_fetch_little_16 374 (bigobj_hdrbuf 375 + offsetof (struct external_filehdr_bigobj, machine)); 376 ocr->is_big_endian = 0; 377 ocr->is_bigobj = 1; 378 ocr->nscns = simple_object_fetch_little_32 379 (bigobj_hdrbuf 380 + offsetof (struct external_filehdr_bigobj, nscns)); 381 ocr->symptr = simple_object_fetch_little_32 382 (bigobj_hdrbuf 383 + offsetof (struct external_filehdr_bigobj, symptr)); 384 ocr->nsyms = simple_object_fetch_little_32 385 (bigobj_hdrbuf 386 + offsetof (struct external_filehdr_bigobj, nsyms)); 387 ocr->flags = simple_object_fetch_little_32 388 (bigobj_hdrbuf 389 + offsetof (struct external_filehdr_bigobj, flags)); 390 ocr->scnhdr_offset = sizeof (struct external_filehdr_bigobj); 391 392 return (void *) ocr; 393 } 394 395 /* Regular COFF. */ 396 is_big_endian = coff_magic[i].is_big_endian; 397 398 magic = is_big_endian ? magic_big : magic_little; 399 fetch_16 = (is_big_endian 400 ? simple_object_fetch_big_16 401 : simple_object_fetch_little_16); 402 fetch_32 = (is_big_endian 403 ? simple_object_fetch_big_32 404 : simple_object_fetch_little_32); 405 406 if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof (struct external_filehdr), 407 errmsg, err)) 408 return NULL; 409 410 flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags)); 411 if ((flags & coff_magic[i].non_object_flags) != 0) 412 { 413 *errmsg = "not relocatable object file"; 414 *err = 0; 415 return NULL; 416 } 417 418 ocr = XNEW (struct simple_object_coff_read); 419 ocr->magic = magic; 420 ocr->is_big_endian = is_big_endian; 421 ocr->is_bigobj = 0; 422 ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns)); 423 ocr->symptr = fetch_32 (hdrbuf 424 + offsetof (struct external_filehdr, f_symptr)); 425 ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms)); 426 ocr->flags = flags; 427 ocr->scnhdr_offset = (sizeof (struct external_filehdr) 428 + fetch_16 (hdrbuf + offsetof (struct external_filehdr, 429 f_opthdr))); 430 431 return (void *) ocr; 432 } 433 434 /* Read the string table in a COFF file. */ 435 436 static char * 437 simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size, 438 const char **errmsg, int *err) 439 { 440 struct simple_object_coff_read *ocr = 441 (struct simple_object_coff_read *) sobj->data; 442 off_t strtab_offset; 443 unsigned char strsizebuf[4]; 444 size_t strsize; 445 char *strtab; 446 size_t sym_size; 447 448 /* Symbol size depends on format. */ 449 sym_size = ocr->is_bigobj ? sizeof (struct external_syment_bigobj) 450 : sizeof (struct external_syment); 451 452 strtab_offset = sobj->offset + ocr->symptr + ocr->nsyms * sym_size; 453 if (!simple_object_internal_read (sobj->descriptor, strtab_offset, 454 strsizebuf, 4, errmsg, err)) 455 return NULL; 456 strsize = (ocr->is_big_endian 457 ? simple_object_fetch_big_32 (strsizebuf) 458 : simple_object_fetch_little_32 (strsizebuf)); 459 strtab = XNEWVEC (char, strsize); 460 if (!simple_object_internal_read (sobj->descriptor, strtab_offset, 461 (unsigned char *) strtab, strsize, errmsg, 462 err)) 463 { 464 XDELETEVEC (strtab); 465 return NULL; 466 } 467 *strtab_size = strsize; 468 return strtab; 469 } 470 471 /* Find all sections in a COFF file. */ 472 473 static const char * 474 simple_object_coff_find_sections (simple_object_read *sobj, 475 int (*pfn) (void *, const char *, 476 off_t offset, off_t length), 477 void *data, 478 int *err) 479 { 480 struct simple_object_coff_read *ocr = 481 (struct simple_object_coff_read *) sobj->data; 482 size_t scnhdr_size; 483 unsigned char *scnbuf; 484 const char *errmsg; 485 unsigned int (*fetch_32) (const unsigned char *); 486 unsigned int nscns; 487 char *strtab; 488 size_t strtab_size; 489 unsigned int i; 490 491 scnhdr_size = sizeof (struct external_scnhdr); 492 scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns); 493 if (!simple_object_internal_read (sobj->descriptor, 494 sobj->offset + ocr->scnhdr_offset, 495 scnbuf, scnhdr_size * ocr->nscns, &errmsg, 496 err)) 497 { 498 XDELETEVEC (scnbuf); 499 return errmsg; 500 } 501 502 fetch_32 = (ocr->is_big_endian 503 ? simple_object_fetch_big_32 504 : simple_object_fetch_little_32); 505 506 nscns = ocr->nscns; 507 strtab = NULL; 508 strtab_size = 0; 509 for (i = 0; i < nscns; ++i) 510 { 511 unsigned char *scnhdr; 512 unsigned char *scnname; 513 char namebuf[SCNNMLEN + 1]; 514 char *name; 515 off_t scnptr; 516 unsigned int size; 517 518 scnhdr = scnbuf + i * scnhdr_size; 519 scnname = scnhdr + offsetof (struct external_scnhdr, s_name); 520 memcpy (namebuf, scnname, SCNNMLEN); 521 namebuf[SCNNMLEN] = '\0'; 522 name = &namebuf[0]; 523 if (namebuf[0] == '/') 524 { 525 size_t strindex; 526 char *end; 527 528 strindex = strtol (namebuf + 1, &end, 10); 529 if (*end == '\0') 530 { 531 /* The real section name is found in the string 532 table. */ 533 if (strtab == NULL) 534 { 535 strtab = simple_object_coff_read_strtab (sobj, 536 &strtab_size, 537 &errmsg, err); 538 if (strtab == NULL) 539 { 540 XDELETEVEC (scnbuf); 541 return errmsg; 542 } 543 } 544 545 if (strindex < 4 || strindex >= strtab_size) 546 { 547 XDELETEVEC (strtab); 548 XDELETEVEC (scnbuf); 549 *err = 0; 550 return "section string index out of range"; 551 } 552 553 name = strtab + strindex; 554 } 555 } 556 557 scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr)); 558 size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size)); 559 560 if (!(*pfn) (data, name, scnptr, size)) 561 break; 562 } 563 564 if (strtab != NULL) 565 XDELETEVEC (strtab); 566 XDELETEVEC (scnbuf); 567 568 return NULL; 569 } 570 571 /* Fetch the attributes for an simple_object_read. */ 572 573 static void * 574 simple_object_coff_fetch_attributes (simple_object_read *sobj, 575 const char **errmsg ATTRIBUTE_UNUSED, 576 int *err ATTRIBUTE_UNUSED) 577 { 578 struct simple_object_coff_read *ocr = 579 (struct simple_object_coff_read *) sobj->data; 580 struct simple_object_coff_attributes *ret; 581 582 ret = XNEW (struct simple_object_coff_attributes); 583 ret->magic = ocr->magic; 584 ret->is_big_endian = ocr->is_big_endian; 585 ret->is_bigobj = ocr->is_bigobj; 586 ret->flags = ocr->flags; 587 return ret; 588 } 589 590 /* Release the private data for an simple_object_read. */ 591 592 static void 593 simple_object_coff_release_read (void *data) 594 { 595 XDELETE (data); 596 } 597 598 /* Compare two attributes structures. */ 599 600 static const char * 601 simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err) 602 { 603 struct simple_object_coff_attributes *to = 604 (struct simple_object_coff_attributes *) todata; 605 struct simple_object_coff_attributes *from = 606 (struct simple_object_coff_attributes *) fromdata; 607 608 if (to->magic != from->magic 609 || to->is_big_endian != from->is_big_endian 610 || to->is_bigobj != from->is_bigobj) 611 { 612 *err = 0; 613 return "COFF object format mismatch"; 614 } 615 return NULL; 616 } 617 618 /* Release the private data for an attributes structure. */ 619 620 static void 621 simple_object_coff_release_attributes (void *data) 622 { 623 XDELETE (data); 624 } 625 626 /* Prepare to write out a file. */ 627 628 static void * 629 simple_object_coff_start_write (void *attributes_data, 630 const char **errmsg ATTRIBUTE_UNUSED, 631 int *err ATTRIBUTE_UNUSED) 632 { 633 struct simple_object_coff_attributes *attrs = 634 (struct simple_object_coff_attributes *) attributes_data; 635 struct simple_object_coff_attributes *ret; 636 637 /* We're just going to record the attributes, but we need to make a 638 copy because the user may delete them. */ 639 ret = XNEW (struct simple_object_coff_attributes); 640 *ret = *attrs; 641 return ret; 642 } 643 644 /* Write out a BigObj COFF filehdr. */ 645 646 static int 647 simple_object_coff_write_filehdr_bigobj (simple_object_write *sobj, 648 int descriptor, 649 unsigned int nscns, 650 size_t symtab_offset, 651 unsigned int nsyms, 652 const char **errmsg, int *err) 653 { 654 struct simple_object_coff_attributes *attrs = 655 (struct simple_object_coff_attributes *) sobj->data; 656 unsigned char hdrbuf[sizeof (struct external_filehdr_bigobj)]; 657 unsigned char *hdr; 658 void (*set_16) (unsigned char *, unsigned short); 659 void (*set_32) (unsigned char *, unsigned int); 660 661 hdr = &hdrbuf[0]; 662 663 /* BigObj is always little-endian. */ 664 set_16 = simple_object_set_little_16; 665 set_32 = simple_object_set_little_32; 666 667 memset (hdr, 0, sizeof (struct external_filehdr_bigobj)); 668 669 /* Set BigObj signatures. */ 670 set_16 (hdr + offsetof (struct external_filehdr_bigobj, sig1), 0); 671 set_16 (hdr + offsetof (struct external_filehdr_bigobj, sig2), 0xFFFF); 672 set_16 (hdr + offsetof (struct external_filehdr_bigobj, version), 2); 673 set_16 (hdr + offsetof (struct external_filehdr_bigobj, machine), 674 attrs->magic); 675 /* timdat left as zero. */ 676 /* Copy ClassID. */ 677 memcpy (hdr + offsetof (struct external_filehdr_bigobj, classid), 678 bigobj_magic, 16); 679 /* sizeofdata, flags, metadatasize, metadataoffset left as zero. */ 680 set_32 (hdr + offsetof (struct external_filehdr_bigobj, nscns), nscns); 681 set_32 (hdr + offsetof (struct external_filehdr_bigobj, symptr), 682 symtab_offset); 683 set_32 (hdr + offsetof (struct external_filehdr_bigobj, nsyms), nsyms); 684 685 return simple_object_internal_write (descriptor, 0, hdrbuf, 686 sizeof (struct external_filehdr_bigobj), 687 errmsg, err); 688 } 689 690 /* Write out a COFF filehdr. */ 691 692 static int 693 simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor, 694 unsigned int nscns, size_t symtab_offset, 695 unsigned int nsyms, const char **errmsg, 696 int *err) 697 { 698 struct simple_object_coff_attributes *attrs = 699 (struct simple_object_coff_attributes *) sobj->data; 700 unsigned char hdrbuf[sizeof (struct external_filehdr)]; 701 unsigned char *hdr; 702 void (*set_16) (unsigned char *, unsigned short); 703 void (*set_32) (unsigned char *, unsigned int); 704 705 hdr = &hdrbuf[0]; 706 707 set_16 = (attrs->is_big_endian 708 ? simple_object_set_big_16 709 : simple_object_set_little_16); 710 set_32 = (attrs->is_big_endian 711 ? simple_object_set_big_32 712 : simple_object_set_little_32); 713 714 memset (hdr, 0, sizeof (struct external_filehdr)); 715 716 set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic); 717 set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns); 718 /* f_timdat left as zero. */ 719 set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset); 720 set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms); 721 /* f_opthdr left as zero. */ 722 set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags); 723 724 return simple_object_internal_write (descriptor, 0, hdrbuf, 725 sizeof (struct external_filehdr), 726 errmsg, err); 727 } 728 729 /* Write out a COFF section header. */ 730 731 static int 732 simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor, 733 const char *name, size_t *name_offset, 734 off_t scnhdr_offset, size_t scnsize, 735 off_t offset, unsigned int align, 736 const char **errmsg, int *err) 737 { 738 struct simple_object_coff_attributes *attrs = 739 (struct simple_object_coff_attributes *) sobj->data; 740 void (*set_32) (unsigned char *, unsigned int); 741 unsigned char hdrbuf[sizeof (struct external_scnhdr)]; 742 unsigned char *hdr; 743 size_t namelen; 744 unsigned int flags; 745 746 set_32 = (attrs->is_big_endian 747 ? simple_object_set_big_32 748 : simple_object_set_little_32); 749 750 memset (hdrbuf, 0, sizeof hdrbuf); 751 hdr = &hdrbuf[0]; 752 753 namelen = strlen (name); 754 if (namelen <= SCNNMLEN) 755 strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name, 756 SCNNMLEN); 757 else 758 { 759 snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name), 760 SCNNMLEN, "/%lu", (unsigned long) *name_offset); 761 *name_offset += namelen + 1; 762 } 763 764 /* s_paddr left as zero. */ 765 /* s_vaddr left as zero. */ 766 set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize); 767 set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset); 768 /* s_relptr left as zero. */ 769 /* s_lnnoptr left as zero. */ 770 /* s_nreloc left as zero. */ 771 /* s_nlnno left as zero. */ 772 flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED 773 | IMAGE_SCN_MEM_READ); 774 /* PE can represent alignment up to 13. */ 775 if (align > 13) 776 align = 13; 777 flags |= IMAGE_SCN_ALIGN_POWER_CONST(align); 778 set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags); 779 780 return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf, 781 sizeof (struct external_scnhdr), 782 errmsg, err); 783 } 784 785 /* Write out a complete COFF file. */ 786 787 static const char * 788 simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor, 789 int *err) 790 { 791 struct simple_object_coff_attributes *attrs = 792 (struct simple_object_coff_attributes *) sobj->data; 793 unsigned int nscns, secnum; 794 simple_object_write_section *section; 795 off_t scnhdr_offset; 796 size_t symtab_offset; 797 off_t secsym_offset; 798 unsigned int nsyms; 799 size_t offset; 800 size_t name_offset; 801 const char *errmsg; 802 unsigned char strsizebuf[4]; 803 /* The interface doesn't give us access to the name of the input file 804 yet. We want to use its basename for the FILE symbol. This is 805 what 'gas' uses when told to assemble from stdin. */ 806 const char *source_filename = "fake"; 807 size_t sflen; 808 size_t symsize; 809 void (*set_16) (unsigned char *, unsigned short); 810 void (*set_32) (unsigned char *, unsigned int); 811 812 /* Determine symbol size based on format. */ 813 if (attrs->is_bigobj) 814 symsize = sizeof (struct external_syment_bigobj); 815 else 816 symsize = sizeof (struct external_syment); 817 818 set_16 = (attrs->is_big_endian 819 ? simple_object_set_big_16 820 : simple_object_set_little_16); 821 set_32 = (attrs->is_big_endian 822 ? simple_object_set_big_32 823 : simple_object_set_little_32); 824 825 nscns = 0; 826 for (section = sobj->sections; section != NULL; section = section->next) 827 ++nscns; 828 829 if (attrs->is_bigobj) 830 scnhdr_offset = sizeof (struct external_filehdr_bigobj); 831 else 832 scnhdr_offset = sizeof (struct external_filehdr); 833 offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr); 834 name_offset = 4; 835 for (section = sobj->sections; section != NULL; section = section->next) 836 { 837 size_t mask; 838 size_t new_offset; 839 size_t scnsize; 840 struct simple_object_write_section_buffer *buffer; 841 842 mask = (1U << section->align) - 1; 843 new_offset = offset & mask; 844 new_offset &= ~ mask; 845 while (new_offset > offset) 846 { 847 unsigned char zeroes[16]; 848 size_t write; 849 850 memset (zeroes, 0, sizeof zeroes); 851 write = new_offset - offset; 852 if (write > sizeof zeroes) 853 write = sizeof zeroes; 854 if (!simple_object_internal_write (descriptor, offset, zeroes, write, 855 &errmsg, err)) 856 return errmsg; 857 } 858 859 scnsize = 0; 860 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 861 { 862 if (!simple_object_internal_write (descriptor, offset + scnsize, 863 ((const unsigned char *) 864 buffer->buffer), 865 buffer->size, &errmsg, err)) 866 return errmsg; 867 scnsize += buffer->size; 868 } 869 870 if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name, 871 &name_offset, scnhdr_offset, 872 scnsize, offset, section->align, 873 &errmsg, err)) 874 return errmsg; 875 876 scnhdr_offset += sizeof (struct external_scnhdr); 877 offset += scnsize; 878 } 879 880 /* Symbol table is always half-word aligned. */ 881 offset += (offset & 1); 882 /* There is a file symbol and a section symbol per section, 883 and each of these has a single auxiliary symbol following. */ 884 nsyms = 2 * (nscns + 1); 885 symtab_offset = offset; 886 /* Advance across space reserved for symbol table to locate 887 start of string table. */ 888 offset += nsyms * symsize; 889 890 /* Write out file symbol. */ 891 if (attrs->is_bigobj) 892 { 893 union 894 { 895 struct external_syment_bigobj sym; 896 union external_auxent_bigobj aux; 897 } syms[2]; 898 899 memset (&syms[0], 0, sizeof (syms)); 900 strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); 901 set_32 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); 902 set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); 903 syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; 904 syms[0].sym.e_numaux[0] = 1; 905 /* The name need not be nul-terminated if it fits into the x_fname field 906 directly, but must be if it has to be placed into the string table. */ 907 sflen = strlen (source_filename); 908 if (sflen <= E_FILNMLEN) 909 memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); 910 else 911 { 912 set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); 913 if (!simple_object_internal_write (descriptor, offset + name_offset, 914 ((const unsigned char *) 915 source_filename), 916 sflen + 1, &errmsg, err)) 917 return errmsg; 918 name_offset += strlen (source_filename) + 1; 919 } 920 if (!simple_object_internal_write (descriptor, symtab_offset, 921 (const unsigned char *) &syms[0], 922 sizeof (syms), &errmsg, err)) 923 return errmsg; 924 925 /* Write the string table length, followed by the strings and section 926 symbols in step with each other. */ 927 set_32 (strsizebuf, name_offset); 928 if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, 929 &errmsg, err)) 930 return errmsg; 931 932 name_offset = 4; 933 secsym_offset = symtab_offset + sizeof (syms); 934 memset (&syms[0], 0, sizeof (syms)); 935 set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); 936 syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; 937 syms[0].sym.e_numaux[0] = 1; 938 secnum = 1; 939 940 for (section = sobj->sections; section != NULL; section = section->next) 941 { 942 size_t namelen; 943 size_t scnsize; 944 struct simple_object_write_section_buffer *buffer; 945 946 namelen = strlen (section->name); 947 set_32 (&syms[0].sym.e_scnum[0], secnum++); 948 scnsize = 0; 949 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 950 scnsize += buffer->size; 951 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); 952 if (namelen > SCNNMLEN) 953 { 954 set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); 955 set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); 956 if (!simple_object_internal_write (descriptor, offset + name_offset, 957 ((const unsigned char *) 958 section->name), 959 namelen + 1, &errmsg, err)) 960 return errmsg; 961 name_offset += namelen + 1; 962 } 963 else 964 { 965 memcpy (&syms[0].sym.e.e_name[0], section->name, 966 strlen (section->name)); 967 memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, 968 E_SYMNMLEN - strlen (section->name)); 969 } 970 971 if (!simple_object_internal_write (descriptor, secsym_offset, 972 (const unsigned char *) &syms[0], 973 sizeof (syms), &errmsg, err)) 974 return errmsg; 975 secsym_offset += sizeof (syms); 976 } 977 } 978 else 979 { 980 /* Regular COFF. */ 981 union 982 { 983 struct external_syment sym; 984 union external_auxent aux; 985 } syms[2]; 986 987 memset (&syms[0], 0, sizeof (syms)); 988 strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); 989 set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); 990 set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); 991 syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; 992 syms[0].sym.e_numaux[0] = 1; 993 /* The name need not be nul-terminated if it fits into the x_fname field 994 directly, but must be if it has to be placed into the string table. */ 995 sflen = strlen (source_filename); 996 if (sflen <= E_FILNMLEN) 997 memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); 998 else 999 { 1000 set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); 1001 if (!simple_object_internal_write (descriptor, offset + name_offset, 1002 ((const unsigned char *) 1003 source_filename), 1004 sflen + 1, &errmsg, err)) 1005 return errmsg; 1006 name_offset += strlen (source_filename) + 1; 1007 } 1008 if (!simple_object_internal_write (descriptor, symtab_offset, 1009 (const unsigned char *) &syms[0], 1010 sizeof (syms), &errmsg, err)) 1011 return errmsg; 1012 1013 /* Write the string table length, followed by the strings and section 1014 symbols in step with each other. */ 1015 set_32 (strsizebuf, name_offset); 1016 if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, 1017 &errmsg, err)) 1018 return errmsg; 1019 1020 name_offset = 4; 1021 secsym_offset = symtab_offset + sizeof (syms); 1022 memset (&syms[0], 0, sizeof (syms)); 1023 set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); 1024 syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; 1025 syms[0].sym.e_numaux[0] = 1; 1026 secnum = 1; 1027 1028 for (section = sobj->sections; section != NULL; section = section->next) 1029 { 1030 size_t namelen; 1031 size_t scnsize; 1032 struct simple_object_write_section_buffer *buffer; 1033 1034 namelen = strlen (section->name); 1035 set_16 (&syms[0].sym.e_scnum[0], secnum++); 1036 scnsize = 0; 1037 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 1038 scnsize += buffer->size; 1039 set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); 1040 if (namelen > SCNNMLEN) 1041 { 1042 set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); 1043 set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); 1044 if (!simple_object_internal_write (descriptor, offset + name_offset, 1045 ((const unsigned char *) 1046 section->name), 1047 namelen + 1, &errmsg, err)) 1048 return errmsg; 1049 name_offset += namelen + 1; 1050 } 1051 else 1052 { 1053 memcpy (&syms[0].sym.e.e_name[0], section->name, 1054 strlen (section->name)); 1055 memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, 1056 E_SYMNMLEN - strlen (section->name)); 1057 } 1058 1059 if (!simple_object_internal_write (descriptor, secsym_offset, 1060 (const unsigned char *) &syms[0], 1061 sizeof (syms), &errmsg, err)) 1062 return errmsg; 1063 secsym_offset += sizeof (syms); 1064 } 1065 } 1066 1067 if (attrs->is_bigobj) 1068 { 1069 if (!simple_object_coff_write_filehdr_bigobj (sobj, descriptor, nscns, 1070 symtab_offset, nsyms, 1071 &errmsg, err)) 1072 return errmsg; 1073 } 1074 else 1075 { 1076 if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns, 1077 symtab_offset, nsyms, &errmsg, err)) 1078 return errmsg; 1079 } 1080 1081 return NULL; 1082 } 1083 1084 /* Release the private data for an simple_object_write structure. */ 1085 1086 static void 1087 simple_object_coff_release_write (void *data) 1088 { 1089 XDELETE (data); 1090 } 1091 1092 /* The COFF functions. */ 1093 1094 const struct simple_object_functions simple_object_coff_functions = 1095 { 1096 simple_object_coff_match, 1097 simple_object_coff_find_sections, 1098 simple_object_coff_fetch_attributes, 1099 simple_object_coff_release_read, 1100 simple_object_coff_attributes_merge, 1101 simple_object_coff_release_attributes, 1102 simple_object_coff_start_write, 1103 simple_object_coff_write_to_file, 1104 simple_object_coff_release_write, 1105 NULL 1106 }; 1107