1 /* simple-object-mach-o.c -- routines to manipulate Mach-O object files. 2 Copyright 2010 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 <stddef.h> 25 26 #ifdef HAVE_STDLIB_H 27 #include <stdlib.h> 28 #endif 29 30 #ifdef HAVE_STDINT_H 31 #include <stdint.h> 32 #endif 33 34 #ifdef HAVE_STRING_H 35 #include <string.h> 36 #endif 37 38 #ifdef HAVE_INTTYPES_H 39 #include <inttypes.h> 40 #endif 41 42 #include "simple-object-common.h" 43 44 /* Mach-O structures and constants. */ 45 46 /* Mach-O header (32-bit version). */ 47 48 struct mach_o_header_32 49 { 50 unsigned char magic[4]; /* Magic number. */ 51 unsigned char cputype[4]; /* CPU that this object is for. */ 52 unsigned char cpusubtype[4]; /* CPU subtype. */ 53 unsigned char filetype[4]; /* Type of file. */ 54 unsigned char ncmds[4]; /* Number of load commands. */ 55 unsigned char sizeofcmds[4]; /* Total size of load commands. */ 56 unsigned char flags[4]; /* Flags for special featues. */ 57 }; 58 59 /* Mach-O header (64-bit version). */ 60 61 struct mach_o_header_64 62 { 63 unsigned char magic[4]; /* Magic number. */ 64 unsigned char cputype[4]; /* CPU that this object is for. */ 65 unsigned char cpusubtype[4]; /* CPU subtype. */ 66 unsigned char filetype[4]; /* Type of file. */ 67 unsigned char ncmds[4]; /* Number of load commands. */ 68 unsigned char sizeofcmds[4]; /* Total size of load commands. */ 69 unsigned char flags[4]; /* Flags for special featues. */ 70 unsigned char reserved[4]; /* Reserved. Duh. */ 71 }; 72 73 /* For magic field in header. */ 74 75 #define MACH_O_MH_MAGIC 0xfeedface 76 #define MACH_O_MH_MAGIC_64 0xfeedfacf 77 78 /* For filetype field in header. */ 79 80 #define MACH_O_MH_OBJECT 0x01 81 82 /* A Mach-O file is a list of load commands. This is the header of a 83 load command. */ 84 85 struct mach_o_load_command 86 { 87 unsigned char cmd[4]; /* The type of load command. */ 88 unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 89 }; 90 91 /* For cmd field in load command. */ 92 93 #define MACH_O_LC_SEGMENT 0x01 94 #define MACH_O_LC_SEGMENT_64 0x19 95 96 /* LC_SEGMENT load command. */ 97 98 struct mach_o_segment_command_32 99 { 100 unsigned char cmd[4]; /* The type of load command (LC_SEGMENT). */ 101 unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 102 unsigned char segname[16]; /* Name of this segment. */ 103 unsigned char vmaddr[4]; /* Virtual memory address of this segment. */ 104 unsigned char vmsize[4]; /* Size there, in bytes. */ 105 unsigned char fileoff[4]; /* Offset in bytes of the data to be mapped. */ 106 unsigned char filesize[4]; /* Size in bytes on disk. */ 107 unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ 108 unsigned char initprot[4]; /* Initial vmem protection. */ 109 unsigned char nsects[4]; /* Number of sections in this segment. */ 110 unsigned char flags[4]; /* Flags that affect the loading. */ 111 }; 112 113 /* LC_SEGMENT_64 load command. */ 114 115 struct mach_o_segment_command_64 116 { 117 unsigned char cmd[4]; /* The type of load command (LC_SEGMENT_64). */ 118 unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 119 unsigned char segname[16]; /* Name of this segment. */ 120 unsigned char vmaddr[8]; /* Virtual memory address of this segment. */ 121 unsigned char vmsize[8]; /* Size there, in bytes. */ 122 unsigned char fileoff[8]; /* Offset in bytes of the data to be mapped. */ 123 unsigned char filesize[8]; /* Size in bytes on disk. */ 124 unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ 125 unsigned char initprot[4]; /* Initial vmem protection. */ 126 unsigned char nsects[4]; /* Number of sections in this segment. */ 127 unsigned char flags[4]; /* Flags that affect the loading. */ 128 }; 129 130 /* 32-bit section header. */ 131 132 struct mach_o_section_32 133 { 134 unsigned char sectname[16]; /* Section name. */ 135 unsigned char segname[16]; /* Segment that the section belongs to. */ 136 unsigned char addr[4]; /* Address of this section in memory. */ 137 unsigned char size[4]; /* Size in bytes of this section. */ 138 unsigned char offset[4]; /* File offset of this section. */ 139 unsigned char align[4]; /* log2 of this section's alignment. */ 140 unsigned char reloff[4]; /* File offset of this section's relocs. */ 141 unsigned char nreloc[4]; /* Number of relocs for this section. */ 142 unsigned char flags[4]; /* Section flags/attributes. */ 143 unsigned char reserved1[4]; 144 unsigned char reserved2[4]; 145 }; 146 147 /* 64-bit section header. */ 148 149 struct mach_o_section_64 150 { 151 unsigned char sectname[16]; /* Section name. */ 152 unsigned char segname[16]; /* Segment that the section belongs to. */ 153 unsigned char addr[8]; /* Address of this section in memory. */ 154 unsigned char size[8]; /* Size in bytes of this section. */ 155 unsigned char offset[4]; /* File offset of this section. */ 156 unsigned char align[4]; /* log2 of this section's alignment. */ 157 unsigned char reloff[4]; /* File offset of this section's relocs. */ 158 unsigned char nreloc[4]; /* Number of relocs for this section. */ 159 unsigned char flags[4]; /* Section flags/attributes. */ 160 unsigned char reserved1[4]; 161 unsigned char reserved2[4]; 162 unsigned char reserved3[4]; 163 }; 164 165 /* Flags for Mach-O sections. */ 166 167 #define MACH_O_S_ATTR_DEBUG 0x02000000 168 169 /* The length of a segment or section name. */ 170 171 #define MACH_O_NAME_LEN (16) 172 173 /* A GNU specific extension for long section names. */ 174 175 #define GNU_SECTION_NAMES "__section_names" 176 177 /* Private data for an simple_object_read. */ 178 179 struct simple_object_mach_o_read 180 { 181 /* User specified segment name. */ 182 char *segment_name; 183 /* Magic number. */ 184 unsigned int magic; 185 /* Whether this file is big-endian. */ 186 int is_big_endian; 187 /* CPU type from header. */ 188 unsigned int cputype; 189 /* CPU subtype from header. */ 190 unsigned int cpusubtype; 191 /* Number of commands, from header. */ 192 unsigned int ncmds; 193 /* Flags from header. */ 194 unsigned int flags; 195 /* Reserved field from header, only used on 64-bit. */ 196 unsigned int reserved; 197 }; 198 199 /* Private data for an simple_object_attributes. */ 200 201 struct simple_object_mach_o_attributes 202 { 203 /* Magic number. */ 204 unsigned int magic; 205 /* Whether this file is big-endian. */ 206 int is_big_endian; 207 /* CPU type from header. */ 208 unsigned int cputype; 209 /* CPU subtype from header. */ 210 unsigned int cpusubtype; 211 /* Flags from header. */ 212 unsigned int flags; 213 /* Reserved field from header, only used on 64-bit. */ 214 unsigned int reserved; 215 }; 216 217 /* See if we have a Mach-O file. */ 218 219 static void * 220 simple_object_mach_o_match ( 221 unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], 222 int descriptor, 223 off_t offset, 224 const char *segment_name, 225 const char **errmsg, 226 int *err) 227 { 228 unsigned int magic; 229 int is_big_endian; 230 unsigned int (*fetch_32) (const unsigned char *); 231 unsigned int filetype; 232 struct simple_object_mach_o_read *omr; 233 unsigned char buf[sizeof (struct mach_o_header_64)]; 234 unsigned char *b; 235 236 magic = simple_object_fetch_big_32 (header); 237 if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) 238 is_big_endian = 1; 239 else 240 { 241 magic = simple_object_fetch_little_32 (header); 242 if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) 243 is_big_endian = 0; 244 else 245 { 246 *errmsg = NULL; 247 *err = 0; 248 return NULL; 249 } 250 } 251 252 #ifndef UNSIGNED_64BIT_TYPE 253 if (magic == MACH_O_MH_MAGIC_64) 254 { 255 *errmsg = "64-bit Mach-O objects not supported"; 256 *err = 0; 257 return NULL; 258 } 259 #endif 260 261 /* We require the user to provide a segment name. This is 262 unfortunate but I don't see any good choices here. */ 263 264 if (segment_name == NULL) 265 { 266 *errmsg = "Mach-O file found but no segment name specified"; 267 *err = 0; 268 return NULL; 269 } 270 271 if (strlen (segment_name) > MACH_O_NAME_LEN) 272 { 273 *errmsg = "Mach-O segment name too long"; 274 *err = 0; 275 return NULL; 276 } 277 278 /* The 32-bit and 64-bit headers are similar enough that we can use 279 the same code. */ 280 281 fetch_32 = (is_big_endian 282 ? simple_object_fetch_big_32 283 : simple_object_fetch_little_32); 284 285 if (!simple_object_internal_read (descriptor, offset, buf, 286 (magic == MACH_O_MH_MAGIC 287 ? sizeof (struct mach_o_header_32) 288 : sizeof (struct mach_o_header_64)), 289 errmsg, err)) 290 return NULL; 291 292 b = &buf[0]; 293 294 filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype)); 295 if (filetype != MACH_O_MH_OBJECT) 296 { 297 *errmsg = "Mach-O file is not object file"; 298 *err = 0; 299 return NULL; 300 } 301 302 omr = XNEW (struct simple_object_mach_o_read); 303 omr->segment_name = xstrdup (segment_name); 304 omr->magic = magic; 305 omr->is_big_endian = is_big_endian; 306 omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype)); 307 omr->cpusubtype = (*fetch_32) (b 308 + offsetof (struct mach_o_header_32, 309 cpusubtype)); 310 omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds)); 311 omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags)); 312 if (magic == MACH_O_MH_MAGIC) 313 omr->reserved = 0; 314 else 315 omr->reserved = (*fetch_32) (b 316 + offsetof (struct mach_o_header_64, 317 reserved)); 318 319 return (void *) omr; 320 } 321 322 /* Get the file offset and size from a section header. */ 323 324 static void 325 simple_object_mach_o_section_info (int is_big_endian, int is_32, 326 const unsigned char *sechdr, off_t *offset, 327 size_t *size) 328 { 329 unsigned int (*fetch_32) (const unsigned char *); 330 ulong_type (*fetch_64) (const unsigned char *); 331 332 fetch_32 = (is_big_endian 333 ? simple_object_fetch_big_32 334 : simple_object_fetch_little_32); 335 336 fetch_64 = NULL; 337 #ifdef UNSIGNED_64BIT_TYPE 338 fetch_64 = (is_big_endian 339 ? simple_object_fetch_big_64 340 : simple_object_fetch_little_64); 341 #endif 342 343 if (is_32) 344 { 345 *offset = fetch_32 (sechdr 346 + offsetof (struct mach_o_section_32, offset)); 347 *size = fetch_32 (sechdr 348 + offsetof (struct mach_o_section_32, size)); 349 } 350 else 351 { 352 *offset = fetch_32 (sechdr 353 + offsetof (struct mach_o_section_64, offset)); 354 *size = fetch_64 (sechdr 355 + offsetof (struct mach_o_section_64, size)); 356 } 357 } 358 359 /* Handle a segment in a Mach-O file. Return 1 if we should continue, 360 0 if the caller should return. */ 361 362 static int 363 simple_object_mach_o_segment (simple_object_read *sobj, off_t offset, 364 const unsigned char *segbuf, 365 int (*pfn) (void *, const char *, off_t offset, 366 off_t length), 367 void *data, 368 const char **errmsg, int *err) 369 { 370 struct simple_object_mach_o_read *omr = 371 (struct simple_object_mach_o_read *) sobj->data; 372 unsigned int (*fetch_32) (const unsigned char *); 373 int is_32; 374 size_t seghdrsize; 375 size_t sechdrsize; 376 size_t segname_offset; 377 size_t sectname_offset; 378 unsigned int nsects; 379 unsigned char *secdata; 380 unsigned int i; 381 unsigned int strtab_index; 382 char *strtab; 383 size_t strtab_size; 384 385 fetch_32 = (omr->is_big_endian 386 ? simple_object_fetch_big_32 387 : simple_object_fetch_little_32); 388 389 is_32 = omr->magic == MACH_O_MH_MAGIC; 390 391 if (is_32) 392 { 393 seghdrsize = sizeof (struct mach_o_segment_command_32); 394 sechdrsize = sizeof (struct mach_o_section_32); 395 segname_offset = offsetof (struct mach_o_section_32, segname); 396 sectname_offset = offsetof (struct mach_o_section_32, sectname); 397 nsects = (*fetch_32) (segbuf 398 + offsetof (struct mach_o_segment_command_32, 399 nsects)); 400 } 401 else 402 { 403 seghdrsize = sizeof (struct mach_o_segment_command_64); 404 sechdrsize = sizeof (struct mach_o_section_64); 405 segname_offset = offsetof (struct mach_o_section_64, segname); 406 sectname_offset = offsetof (struct mach_o_section_64, sectname); 407 nsects = (*fetch_32) (segbuf 408 + offsetof (struct mach_o_segment_command_64, 409 nsects)); 410 } 411 412 secdata = XNEWVEC (unsigned char, nsects * sechdrsize); 413 if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize, 414 secdata, nsects * sechdrsize, errmsg, err)) 415 { 416 XDELETEVEC (secdata); 417 return 0; 418 } 419 420 /* Scan for a __section_names section. This is in effect a GNU 421 extension that permits section names longer than 16 chars. */ 422 423 for (i = 0; i < nsects; ++i) 424 { 425 size_t nameoff; 426 427 nameoff = i * sechdrsize + segname_offset; 428 if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0) 429 continue; 430 nameoff = i * sechdrsize + sectname_offset; 431 if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) 432 break; 433 } 434 435 strtab_index = i; 436 if (strtab_index >= nsects) 437 { 438 strtab = NULL; 439 strtab_size = 0; 440 } 441 else 442 { 443 off_t strtab_offset; 444 445 simple_object_mach_o_section_info (omr->is_big_endian, is_32, 446 secdata + strtab_index * sechdrsize, 447 &strtab_offset, &strtab_size); 448 strtab = XNEWVEC (char, strtab_size); 449 if (!simple_object_internal_read (sobj->descriptor, 450 sobj->offset + strtab_offset, 451 (unsigned char *) strtab, strtab_size, 452 errmsg, err)) 453 { 454 XDELETEVEC (strtab); 455 XDELETEVEC (secdata); 456 return 0; 457 } 458 } 459 460 /* Process the sections. */ 461 462 for (i = 0; i < nsects; ++i) 463 { 464 const unsigned char *sechdr; 465 char namebuf[MACH_O_NAME_LEN + 1]; 466 char *name; 467 off_t secoffset; 468 size_t secsize; 469 470 if (i == strtab_index) 471 continue; 472 473 sechdr = secdata + i * sechdrsize; 474 475 if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0) 476 continue; 477 478 memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); 479 namebuf[MACH_O_NAME_LEN] = '\0'; 480 481 name = &namebuf[0]; 482 if (strtab != NULL && name[0] == '_' && name[1] == '_') 483 { 484 unsigned long stringoffset; 485 486 if (sscanf (name + 2, "%08lX", &stringoffset) == 1) 487 { 488 if (stringoffset >= strtab_size) 489 { 490 *errmsg = "section name offset out of range"; 491 *err = 0; 492 XDELETEVEC (strtab); 493 XDELETEVEC (secdata); 494 return 0; 495 } 496 497 name = strtab + stringoffset; 498 } 499 } 500 501 simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr, 502 &secoffset, &secsize); 503 504 if (!(*pfn) (data, name, secoffset, secsize)) 505 { 506 *errmsg = NULL; 507 *err = 0; 508 XDELETEVEC (strtab); 509 XDELETEVEC (secdata); 510 return 0; 511 } 512 } 513 514 XDELETEVEC (strtab); 515 XDELETEVEC (secdata); 516 517 return 1; 518 } 519 520 /* Find all sections in a Mach-O file. */ 521 522 static const char * 523 simple_object_mach_o_find_sections (simple_object_read *sobj, 524 int (*pfn) (void *, const char *, 525 off_t offset, off_t length), 526 void *data, 527 int *err) 528 { 529 struct simple_object_mach_o_read *omr = 530 (struct simple_object_mach_o_read *) sobj->data; 531 off_t offset; 532 size_t seghdrsize; 533 unsigned int (*fetch_32) (const unsigned char *); 534 const char *errmsg; 535 unsigned int i; 536 537 if (omr->magic == MACH_O_MH_MAGIC) 538 { 539 offset = sizeof (struct mach_o_header_32); 540 seghdrsize = sizeof (struct mach_o_segment_command_32); 541 } 542 else 543 { 544 offset = sizeof (struct mach_o_header_64); 545 seghdrsize = sizeof (struct mach_o_segment_command_64); 546 } 547 548 fetch_32 = (omr->is_big_endian 549 ? simple_object_fetch_big_32 550 : simple_object_fetch_little_32); 551 552 for (i = 0; i < omr->ncmds; ++i) 553 { 554 unsigned char loadbuf[sizeof (struct mach_o_load_command)]; 555 unsigned int cmd; 556 unsigned int cmdsize; 557 558 if (!simple_object_internal_read (sobj->descriptor, 559 sobj->offset + offset, 560 loadbuf, 561 sizeof (struct mach_o_load_command), 562 &errmsg, err)) 563 return errmsg; 564 565 cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd)); 566 cmdsize = (*fetch_32) (loadbuf 567 + offsetof (struct mach_o_load_command, cmdsize)); 568 569 if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64) 570 { 571 unsigned char segbuf[sizeof (struct mach_o_segment_command_64)]; 572 int r; 573 574 if (!simple_object_internal_read (sobj->descriptor, 575 sobj->offset + offset, 576 segbuf, seghdrsize, &errmsg, err)) 577 return errmsg; 578 579 r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn, 580 data, &errmsg, err); 581 if (!r) 582 return errmsg; 583 } 584 585 offset += cmdsize; 586 } 587 588 return NULL; 589 } 590 591 /* Fetch the attributes for an simple_object_read. */ 592 593 static void * 594 simple_object_mach_o_fetch_attributes (simple_object_read *sobj, 595 const char **errmsg ATTRIBUTE_UNUSED, 596 int *err ATTRIBUTE_UNUSED) 597 { 598 struct simple_object_mach_o_read *omr = 599 (struct simple_object_mach_o_read *) sobj->data; 600 struct simple_object_mach_o_attributes *ret; 601 602 ret = XNEW (struct simple_object_mach_o_attributes); 603 ret->magic = omr->magic; 604 ret->is_big_endian = omr->is_big_endian; 605 ret->cputype = omr->cputype; 606 ret->cpusubtype = omr->cpusubtype; 607 ret->flags = omr->flags; 608 ret->reserved = omr->reserved; 609 return ret; 610 } 611 612 /* Release the private data for an simple_object_read. */ 613 614 static void 615 simple_object_mach_o_release_read (void *data) 616 { 617 struct simple_object_mach_o_read *omr = 618 (struct simple_object_mach_o_read *) data; 619 620 free (omr->segment_name); 621 XDELETE (omr); 622 } 623 624 /* Compare two attributes structures. */ 625 626 static const char * 627 simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err) 628 { 629 struct simple_object_mach_o_attributes *to = 630 (struct simple_object_mach_o_attributes *) todata; 631 struct simple_object_mach_o_attributes *from = 632 (struct simple_object_mach_o_attributes *) fromdata; 633 634 if (to->magic != from->magic 635 || to->is_big_endian != from->is_big_endian 636 || to->cputype != from->cputype) 637 { 638 *err = 0; 639 return "Mach-O object format mismatch"; 640 } 641 return NULL; 642 } 643 644 /* Release the private data for an attributes structure. */ 645 646 static void 647 simple_object_mach_o_release_attributes (void *data) 648 { 649 XDELETE (data); 650 } 651 652 /* Prepare to write out a file. */ 653 654 static void * 655 simple_object_mach_o_start_write (void *attributes_data, 656 const char **errmsg ATTRIBUTE_UNUSED, 657 int *err ATTRIBUTE_UNUSED) 658 { 659 struct simple_object_mach_o_attributes *attrs = 660 (struct simple_object_mach_o_attributes *) attributes_data; 661 struct simple_object_mach_o_attributes *ret; 662 663 /* We're just going to record the attributes, but we need to make a 664 copy because the user may delete them. */ 665 ret = XNEW (struct simple_object_mach_o_attributes); 666 *ret = *attrs; 667 return ret; 668 } 669 670 /* Write out the header of a Mach-O file. */ 671 672 static int 673 simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor, 674 size_t nsects, const char **errmsg, 675 int *err) 676 { 677 struct simple_object_mach_o_attributes *attrs = 678 (struct simple_object_mach_o_attributes *) sobj->data; 679 void (*set_32) (unsigned char *, unsigned int); 680 unsigned char hdrbuf[sizeof (struct mach_o_header_64)]; 681 unsigned char *hdr; 682 size_t wrsize; 683 684 set_32 = (attrs->is_big_endian 685 ? simple_object_set_big_32 686 : simple_object_set_little_32); 687 688 memset (hdrbuf, 0, sizeof hdrbuf); 689 690 /* The 32-bit and 64-bit headers start out the same. */ 691 692 hdr = &hdrbuf[0]; 693 set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic); 694 set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype); 695 set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype), 696 attrs->cpusubtype); 697 set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT); 698 set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1); 699 set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags); 700 if (attrs->magic == MACH_O_MH_MAGIC) 701 { 702 wrsize = sizeof (struct mach_o_header_32); 703 set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds), 704 (sizeof (struct mach_o_segment_command_32) 705 + nsects * sizeof (struct mach_o_section_32))); 706 } 707 else 708 { 709 set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds), 710 (sizeof (struct mach_o_segment_command_64) 711 + nsects * sizeof (struct mach_o_section_64))); 712 set_32 (hdr + offsetof (struct mach_o_header_64, reserved), 713 attrs->reserved); 714 wrsize = sizeof (struct mach_o_header_64); 715 } 716 717 return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize, 718 errmsg, err); 719 } 720 721 /* Write a Mach-O section header. */ 722 723 static int 724 simple_object_mach_o_write_section_header (simple_object_write *sobj, 725 int descriptor, 726 size_t sechdr_offset, 727 const char *name, size_t secaddr, 728 size_t secsize, size_t offset, 729 unsigned int align, 730 const char **errmsg, int *err) 731 { 732 struct simple_object_mach_o_attributes *attrs = 733 (struct simple_object_mach_o_attributes *) sobj->data; 734 void (*set_32) (unsigned char *, unsigned int); 735 unsigned char hdrbuf[sizeof (struct mach_o_section_64)]; 736 unsigned char *hdr; 737 size_t sechdrsize; 738 739 set_32 = (attrs->is_big_endian 740 ? simple_object_set_big_32 741 : simple_object_set_little_32); 742 743 memset (hdrbuf, 0, sizeof hdrbuf); 744 745 hdr = &hdrbuf[0]; 746 if (attrs->magic == MACH_O_MH_MAGIC) 747 { 748 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname), 749 name, MACH_O_NAME_LEN); 750 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname), 751 sobj->segment_name, MACH_O_NAME_LEN); 752 set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr); 753 set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize); 754 set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset); 755 set_32 (hdr + offsetof (struct mach_o_section_32, align), align); 756 /* reloff left as zero. */ 757 /* nreloc left as zero. */ 758 set_32 (hdr + offsetof (struct mach_o_section_32, flags), 759 MACH_O_S_ATTR_DEBUG); 760 /* reserved1 left as zero. */ 761 /* reserved2 left as zero. */ 762 sechdrsize = sizeof (struct mach_o_section_32); 763 } 764 else 765 { 766 #ifdef UNSIGNED_64BIT_TYPE 767 void (*set_64) (unsigned char *, ulong_type); 768 769 set_64 = (attrs->is_big_endian 770 ? simple_object_set_big_64 771 : simple_object_set_little_64); 772 773 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname), 774 name, MACH_O_NAME_LEN); 775 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname), 776 sobj->segment_name, MACH_O_NAME_LEN); 777 set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr); 778 set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize); 779 set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset); 780 set_32 (hdr + offsetof (struct mach_o_section_64, align), align); 781 /* reloff left as zero. */ 782 /* nreloc left as zero. */ 783 set_32 (hdr + offsetof (struct mach_o_section_64, flags), 784 MACH_O_S_ATTR_DEBUG); 785 /* reserved1 left as zero. */ 786 /* reserved2 left as zero. */ 787 /* reserved3 left as zero. */ 788 #endif 789 sechdrsize = sizeof (struct mach_o_section_64); 790 } 791 792 return simple_object_internal_write (descriptor, sechdr_offset, hdr, 793 sechdrsize, errmsg, err); 794 } 795 796 /* Write out the single segment and the sections of a Mach-O file. */ 797 798 static int 799 simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, 800 size_t nsects, const char **errmsg, 801 int *err) 802 { 803 struct simple_object_mach_o_attributes *attrs = 804 (struct simple_object_mach_o_attributes *) sobj->data; 805 void (*set_32) (unsigned char *, unsigned int); 806 size_t hdrsize; 807 size_t seghdrsize; 808 size_t sechdrsize; 809 size_t cmdsize; 810 size_t offset; 811 size_t sechdr_offset; 812 size_t secaddr; 813 unsigned int name_offset; 814 simple_object_write_section *section; 815 unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; 816 unsigned char *hdr; 817 818 set_32 = (attrs->is_big_endian 819 ? simple_object_set_big_32 820 : simple_object_set_little_32); 821 822 /* Write out the sections first. */ 823 824 if (attrs->magic == MACH_O_MH_MAGIC) 825 { 826 hdrsize = sizeof (struct mach_o_header_32); 827 seghdrsize = sizeof (struct mach_o_segment_command_32); 828 sechdrsize = sizeof (struct mach_o_section_32); 829 } 830 else 831 { 832 hdrsize = sizeof (struct mach_o_header_64); 833 seghdrsize = sizeof (struct mach_o_segment_command_64); 834 sechdrsize = sizeof (struct mach_o_section_64); 835 } 836 837 sechdr_offset = hdrsize + seghdrsize; 838 cmdsize = seghdrsize + nsects * sechdrsize; 839 offset = hdrsize + cmdsize; 840 name_offset = 0; 841 secaddr = 0; 842 843 for (section = sobj->sections; section != NULL; section = section->next) 844 { 845 size_t mask; 846 size_t new_offset; 847 size_t secsize; 848 struct simple_object_write_section_buffer *buffer; 849 char namebuf[MACH_O_NAME_LEN + 1]; 850 851 mask = (1U << section->align) - 1; 852 new_offset = offset + mask; 853 new_offset &= ~ mask; 854 while (new_offset > offset) 855 { 856 unsigned char zeroes[16]; 857 size_t write; 858 859 memset (zeroes, 0, sizeof zeroes); 860 write = new_offset - offset; 861 if (write > sizeof zeroes) 862 write = sizeof zeroes; 863 if (!simple_object_internal_write (descriptor, offset, zeroes, write, 864 errmsg, err)) 865 return 0; 866 offset += write; 867 } 868 869 secsize = 0; 870 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 871 { 872 if (!simple_object_internal_write (descriptor, offset + secsize, 873 ((const unsigned char *) 874 buffer->buffer), 875 buffer->size, errmsg, err)) 876 return 0; 877 secsize += buffer->size; 878 } 879 880 snprintf (namebuf, sizeof namebuf, "__%08X", name_offset); 881 if (!simple_object_mach_o_write_section_header (sobj, descriptor, 882 sechdr_offset, namebuf, 883 secaddr, secsize, offset, 884 section->align, 885 errmsg, err)) 886 return 0; 887 888 sechdr_offset += sechdrsize; 889 offset += secsize; 890 name_offset += strlen (section->name) + 1; 891 secaddr += secsize; 892 } 893 894 /* Write out the section names. */ 895 896 if (!simple_object_mach_o_write_section_header (sobj, descriptor, 897 sechdr_offset, 898 GNU_SECTION_NAMES, secaddr, 899 name_offset, offset, 0, 900 errmsg, err)) 901 return 0; 902 903 for (section = sobj->sections; section != NULL; section = section->next) 904 { 905 size_t namelen; 906 907 namelen = strlen (section->name) + 1; 908 if (!simple_object_internal_write (descriptor, offset, 909 (const unsigned char *) section->name, 910 namelen, errmsg, err)) 911 return 0; 912 offset += namelen; 913 } 914 915 /* Write out the segment header. */ 916 917 memset (hdrbuf, 0, sizeof hdrbuf); 918 919 hdr = &hdrbuf[0]; 920 if (attrs->magic == MACH_O_MH_MAGIC) 921 { 922 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd), 923 MACH_O_LC_SEGMENT); 924 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize), 925 cmdsize); 926 strncpy (((char *) hdr 927 + offsetof (struct mach_o_segment_command_32, segname)), 928 sobj->segment_name, MACH_O_NAME_LEN); 929 /* vmaddr left as zero. */ 930 /* vmsize left as zero. */ 931 set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff), 932 hdrsize + cmdsize); 933 set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize), 934 offset - (hdrsize + cmdsize)); 935 /* maxprot left as zero. */ 936 /* initprot left as zero. */ 937 set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects), 938 nsects); 939 /* flags left as zero. */ 940 } 941 else 942 { 943 #ifdef UNSIGNED_64BIT_TYPE 944 void (*set_64) (unsigned char *, ulong_type); 945 946 set_64 = (attrs->is_big_endian 947 ? simple_object_set_big_64 948 : simple_object_set_little_64); 949 950 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd), 951 MACH_O_LC_SEGMENT); 952 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize), 953 cmdsize); 954 strncpy (((char *) hdr 955 + offsetof (struct mach_o_segment_command_64, segname)), 956 sobj->segment_name, MACH_O_NAME_LEN); 957 /* vmaddr left as zero. */ 958 /* vmsize left as zero. */ 959 set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff), 960 hdrsize + cmdsize); 961 set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize), 962 offset - (hdrsize + cmdsize)); 963 /* maxprot left as zero. */ 964 /* initprot left as zero. */ 965 set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects), 966 nsects); 967 /* flags left as zero. */ 968 #endif 969 } 970 971 return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize, 972 errmsg, err); 973 } 974 975 /* Write out a complete Mach-O file. */ 976 977 static const char * 978 simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, 979 int *err) 980 { 981 size_t nsects; 982 simple_object_write_section *section; 983 const char *errmsg; 984 985 /* Start at 1 for symbol_names section. */ 986 nsects = 1; 987 for (section = sobj->sections; section != NULL; section = section->next) 988 ++nsects; 989 990 if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, 991 &errmsg, err)) 992 return errmsg; 993 994 if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects, 995 &errmsg, err)) 996 return errmsg; 997 998 return NULL; 999 } 1000 1001 /* Release the private data for an simple_object_write structure. */ 1002 1003 static void 1004 simple_object_mach_o_release_write (void *data) 1005 { 1006 XDELETE (data); 1007 } 1008 1009 /* The Mach-O functions. */ 1010 1011 const struct simple_object_functions simple_object_mach_o_functions = 1012 { 1013 simple_object_mach_o_match, 1014 simple_object_mach_o_find_sections, 1015 simple_object_mach_o_fetch_attributes, 1016 simple_object_mach_o_release_read, 1017 simple_object_mach_o_attributes_merge, 1018 simple_object_mach_o_release_attributes, 1019 simple_object_mach_o_start_write, 1020 simple_object_mach_o_write_to_file, 1021 simple_object_mach_o_release_write 1022 }; 1023