Mercurial > hg > CbC > CbC_gcc
comparison libiberty/simple-object-mach-o.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | 561a7518be6b |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* simple-object-mach-o.c -- routines to manipulate Mach-O object files. | 1 /* simple-object-mach-o.c -- routines to manipulate Mach-O object files. |
2 Copyright 2010 Free Software Foundation, Inc. | 2 Copyright (C) 2010-2017 Free Software Foundation, Inc. |
3 Written by Ian Lance Taylor, Google. | 3 Written by Ian Lance Taylor, Google. |
4 | 4 |
5 This program is free software; you can redistribute it and/or modify it | 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 | 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 | 7 Free Software Foundation; either version 2, or (at your option) any |
171 #define MACH_O_NAME_LEN (16) | 171 #define MACH_O_NAME_LEN (16) |
172 | 172 |
173 /* A GNU specific extension for long section names. */ | 173 /* A GNU specific extension for long section names. */ |
174 | 174 |
175 #define GNU_SECTION_NAMES "__section_names" | 175 #define GNU_SECTION_NAMES "__section_names" |
176 | |
177 /* A GNU-specific extension to wrap multiple sections using three | |
178 mach-o sections within a given segment. The section '__wrapper_sects' | |
179 is subdivided according to the index '__wrapper_index' and each sub | |
180 sect is named according to the names supplied in '__wrapper_names'. */ | |
181 | |
182 #define GNU_WRAPPER_SECTS "__wrapper_sects" | |
183 #define GNU_WRAPPER_INDEX "__wrapper_index" | |
184 #define GNU_WRAPPER_NAMES "__wrapper_names" | |
176 | 185 |
177 /* Private data for an simple_object_read. */ | 186 /* Private data for an simple_object_read. */ |
178 | 187 |
179 struct simple_object_mach_o_read | 188 struct simple_object_mach_o_read |
180 { | 189 { |
212 unsigned int flags; | 221 unsigned int flags; |
213 /* Reserved field from header, only used on 64-bit. */ | 222 /* Reserved field from header, only used on 64-bit. */ |
214 unsigned int reserved; | 223 unsigned int reserved; |
215 }; | 224 }; |
216 | 225 |
217 /* See if we have a Mach-O file. */ | 226 /* See if we have a Mach-O MH_OBJECT file: |
227 | |
228 A standard MH_OBJECT (from as) will have three load commands: | |
229 0 - LC_SEGMENT/LC_SEGMENT64 | |
230 1 - LC_SYMTAB | |
231 2 - LC_DYSYMTAB | |
232 | |
233 The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment | |
234 containing all the sections. | |
235 | |
236 Files written by simple-object will have only the segment command | |
237 (no symbol tables). */ | |
218 | 238 |
219 static void * | 239 static void * |
220 simple_object_mach_o_match ( | 240 simple_object_mach_o_match ( |
221 unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], | 241 unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], |
222 int descriptor, | 242 int descriptor, |
354 *size = fetch_64 (sechdr | 374 *size = fetch_64 (sechdr |
355 + offsetof (struct mach_o_section_64, size)); | 375 + offsetof (struct mach_o_section_64, size)); |
356 } | 376 } |
357 } | 377 } |
358 | 378 |
359 /* Handle a segment in a Mach-O file. Return 1 if we should continue, | 379 /* Handle a segment in a Mach-O Object file. |
360 0 if the caller should return. */ | 380 |
381 This will callback to the function pfn for each "section found" the meaning | |
382 of which depends on gnu extensions to mach-o: | |
383 | |
384 If we find mach-o sections (with the segment name as specified) which also | |
385 contain: a 'sects' wrapper, an index, and a name table, we expand this into | |
386 as many sections as are specified in the index. In this case, there will | |
387 be a callback for each of these. | |
388 | |
389 We will also allow an extension that permits long names (more than 16 | |
390 characters) to be used with mach-o. In this case, the section name has | |
391 a specific format embedding an index into a name table, and the file must | |
392 contain such name table. | |
393 | |
394 Return 1 if we should continue, 0 if the caller should return. */ | |
395 | |
396 #define SOMO_SECTS_PRESENT 0x01 | |
397 #define SOMO_INDEX_PRESENT 0x02 | |
398 #define SOMO_NAMES_PRESENT 0x04 | |
399 #define SOMO_LONGN_PRESENT 0x08 | |
400 #define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \ | |
401 | SOMO_NAMES_PRESENT) | |
361 | 402 |
362 static int | 403 static int |
363 simple_object_mach_o_segment (simple_object_read *sobj, off_t offset, | 404 simple_object_mach_o_segment (simple_object_read *sobj, off_t offset, |
364 const unsigned char *segbuf, | 405 const unsigned char *segbuf, |
365 int (*pfn) (void *, const char *, off_t offset, | 406 int (*pfn) (void *, const char *, off_t offset, |
376 size_t segname_offset; | 417 size_t segname_offset; |
377 size_t sectname_offset; | 418 size_t sectname_offset; |
378 unsigned int nsects; | 419 unsigned int nsects; |
379 unsigned char *secdata; | 420 unsigned char *secdata; |
380 unsigned int i; | 421 unsigned int i; |
422 unsigned int gnu_sections_found; | |
381 unsigned int strtab_index; | 423 unsigned int strtab_index; |
424 unsigned int index_index; | |
425 unsigned int nametab_index; | |
426 unsigned int sections_index; | |
382 char *strtab; | 427 char *strtab; |
428 char *nametab; | |
429 unsigned char *index; | |
383 size_t strtab_size; | 430 size_t strtab_size; |
431 size_t nametab_size; | |
432 size_t index_size; | |
433 unsigned int n_wrapped_sects; | |
434 size_t wrapper_sect_size; | |
435 off_t wrapper_sect_offset = 0; | |
384 | 436 |
385 fetch_32 = (omr->is_big_endian | 437 fetch_32 = (omr->is_big_endian |
386 ? simple_object_fetch_big_32 | 438 ? simple_object_fetch_big_32 |
387 : simple_object_fetch_little_32); | 439 : simple_object_fetch_little_32); |
388 | 440 |
407 nsects = (*fetch_32) (segbuf | 459 nsects = (*fetch_32) (segbuf |
408 + offsetof (struct mach_o_segment_command_64, | 460 + offsetof (struct mach_o_segment_command_64, |
409 nsects)); | 461 nsects)); |
410 } | 462 } |
411 | 463 |
464 /* Fetch the section headers from the segment command. */ | |
465 | |
412 secdata = XNEWVEC (unsigned char, nsects * sechdrsize); | 466 secdata = XNEWVEC (unsigned char, nsects * sechdrsize); |
413 if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize, | 467 if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize, |
414 secdata, nsects * sechdrsize, errmsg, err)) | 468 secdata, nsects * sechdrsize, errmsg, err)) |
415 { | 469 { |
416 XDELETEVEC (secdata); | 470 XDELETEVEC (secdata); |
417 return 0; | 471 return 0; |
418 } | 472 } |
419 | 473 |
420 /* Scan for a __section_names section. This is in effect a GNU | 474 /* Scan for special sections that signal GNU extensions to the format. */ |
421 extension that permits section names longer than 16 chars. */ | 475 |
422 | 476 gnu_sections_found = 0; |
477 index_index = nsects; | |
478 sections_index = nsects; | |
479 strtab_index = nsects; | |
480 nametab_index = nsects; | |
423 for (i = 0; i < nsects; ++i) | 481 for (i = 0; i < nsects; ++i) |
424 { | 482 { |
425 size_t nameoff; | 483 size_t nameoff; |
426 | 484 |
427 nameoff = i * sechdrsize + segname_offset; | 485 nameoff = i * sechdrsize + segname_offset; |
428 if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0) | 486 if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0) |
429 continue; | 487 continue; |
488 | |
430 nameoff = i * sechdrsize + sectname_offset; | 489 nameoff = i * sechdrsize + sectname_offset; |
431 if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) | 490 if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0) |
432 break; | 491 { |
433 } | 492 nametab_index = i; |
434 | 493 gnu_sections_found |= SOMO_NAMES_PRESENT; |
435 strtab_index = i; | 494 } |
436 if (strtab_index >= nsects) | 495 else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0) |
437 { | 496 { |
438 strtab = NULL; | 497 index_index = i; |
439 strtab_size = 0; | 498 gnu_sections_found |= SOMO_INDEX_PRESENT; |
499 } | |
500 else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0) | |
501 { | |
502 sections_index = i; | |
503 gnu_sections_found |= SOMO_SECTS_PRESENT; | |
504 } | |
505 else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) | |
506 { | |
507 strtab_index = i; | |
508 gnu_sections_found |= SOMO_LONGN_PRESENT; | |
509 } | |
510 } | |
511 | |
512 /* If any of the special wrapper section components is present, then | |
513 they all should be. */ | |
514 | |
515 if ((gnu_sections_found & SOMO_WRAPPING) != 0) | |
516 { | |
517 off_t nametab_offset; | |
518 off_t index_offset; | |
519 | |
520 if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING) | |
521 { | |
522 *errmsg = "GNU Mach-o section wrapper: required section missing"; | |
523 *err = 0; /* No useful errno. */ | |
524 XDELETEVEC (secdata); | |
525 return 0; | |
526 } | |
527 | |
528 /* Fetch the name table. */ | |
529 | |
530 simple_object_mach_o_section_info (omr->is_big_endian, is_32, | |
531 secdata + nametab_index * sechdrsize, | |
532 &nametab_offset, &nametab_size); | |
533 nametab = XNEWVEC (char, nametab_size); | |
534 if (!simple_object_internal_read (sobj->descriptor, | |
535 sobj->offset + nametab_offset, | |
536 (unsigned char *) nametab, nametab_size, | |
537 errmsg, err)) | |
538 { | |
539 XDELETEVEC (nametab); | |
540 XDELETEVEC (secdata); | |
541 return 0; | |
542 } | |
543 | |
544 /* Fetch the index. */ | |
545 | |
546 simple_object_mach_o_section_info (omr->is_big_endian, is_32, | |
547 secdata + index_index * sechdrsize, | |
548 &index_offset, &index_size); | |
549 index = XNEWVEC (unsigned char, index_size); | |
550 if (!simple_object_internal_read (sobj->descriptor, | |
551 sobj->offset + index_offset, | |
552 index, index_size, | |
553 errmsg, err)) | |
554 { | |
555 XDELETEVEC (index); | |
556 XDELETEVEC (nametab); | |
557 XDELETEVEC (secdata); | |
558 return 0; | |
559 } | |
560 | |
561 /* The index contains 4 unsigned ints per sub-section: | |
562 sub-section offset/length, sub-section name/length. | |
563 We fix this for both 32 and 64 bit mach-o for now, since | |
564 other fields limit the maximum size of an object to 4G. */ | |
565 n_wrapped_sects = index_size / 16; | |
566 | |
567 /* Get the parameters for the wrapper too. */ | |
568 simple_object_mach_o_section_info (omr->is_big_endian, is_32, | |
569 secdata + sections_index * sechdrsize, | |
570 &wrapper_sect_offset, | |
571 &wrapper_sect_size); | |
440 } | 572 } |
441 else | 573 else |
574 { | |
575 index = NULL; | |
576 index_size = 0; | |
577 nametab = NULL; | |
578 nametab_size = 0; | |
579 n_wrapped_sects = 0; | |
580 } | |
581 | |
582 /* If we have a long names section, fetch it. */ | |
583 | |
584 if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) | |
442 { | 585 { |
443 off_t strtab_offset; | 586 off_t strtab_offset; |
444 | 587 |
445 simple_object_mach_o_section_info (omr->is_big_endian, is_32, | 588 simple_object_mach_o_section_info (omr->is_big_endian, is_32, |
446 secdata + strtab_index * sechdrsize, | 589 secdata + strtab_index * sechdrsize, |
450 sobj->offset + strtab_offset, | 593 sobj->offset + strtab_offset, |
451 (unsigned char *) strtab, strtab_size, | 594 (unsigned char *) strtab, strtab_size, |
452 errmsg, err)) | 595 errmsg, err)) |
453 { | 596 { |
454 XDELETEVEC (strtab); | 597 XDELETEVEC (strtab); |
598 XDELETEVEC (index); | |
599 XDELETEVEC (nametab); | |
455 XDELETEVEC (secdata); | 600 XDELETEVEC (secdata); |
456 return 0; | 601 return 0; |
457 } | 602 } |
458 } | 603 } |
604 else | |
605 { | |
606 strtab = NULL; | |
607 strtab_size = 0; | |
608 strtab_index = nsects; | |
609 } | |
459 | 610 |
460 /* Process the sections. */ | 611 /* Process the sections. */ |
461 | 612 |
462 for (i = 0; i < nsects; ++i) | 613 for (i = 0; i < nsects; ++i) |
463 { | 614 { |
464 const unsigned char *sechdr; | 615 const unsigned char *sechdr; |
465 char namebuf[MACH_O_NAME_LEN + 1]; | 616 char namebuf[MACH_O_NAME_LEN * 2 + 2]; |
466 char *name; | 617 char *name; |
467 off_t secoffset; | 618 off_t secoffset; |
468 size_t secsize; | 619 size_t secsize; |
469 | 620 int l; |
470 if (i == strtab_index) | 621 |
622 sechdr = secdata + i * sechdrsize; | |
623 | |
624 /* We've already processed the long section names. */ | |
625 | |
626 if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0 | |
627 && i == strtab_index) | |
471 continue; | 628 continue; |
472 | 629 |
473 sechdr = secdata + i * sechdrsize; | 630 /* We only act on the segment named. */ |
474 | 631 |
475 if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0) | 632 if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0) |
476 continue; | 633 continue; |
477 | 634 |
478 memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); | 635 /* Process sections associated with the wrapper. */ |
479 namebuf[MACH_O_NAME_LEN] = '\0'; | 636 |
480 | 637 if ((gnu_sections_found & SOMO_WRAPPING) != 0) |
481 name = &namebuf[0]; | 638 { |
482 if (strtab != NULL && name[0] == '_' && name[1] == '_') | 639 if (i == nametab_index || i == index_index) |
483 { | 640 continue; |
484 unsigned long stringoffset; | 641 |
485 | 642 if (i == sections_index) |
486 if (sscanf (name + 2, "%08lX", &stringoffset) == 1) | |
487 { | 643 { |
488 if (stringoffset >= strtab_size) | 644 unsigned int j; |
645 for (j = 0; j < n_wrapped_sects; ++j) | |
489 { | 646 { |
490 *errmsg = "section name offset out of range"; | 647 unsigned int subsect_offset, subsect_length, name_offset; |
491 *err = 0; | 648 subsect_offset = (*fetch_32) (index + 16 * j); |
492 XDELETEVEC (strtab); | 649 subsect_length = (*fetch_32) (index + 16 * j + 4); |
493 XDELETEVEC (secdata); | 650 name_offset = (*fetch_32) (index + 16 * j + 8); |
494 return 0; | 651 /* We don't need the name_length yet. */ |
652 | |
653 secoffset = wrapper_sect_offset + subsect_offset; | |
654 secsize = subsect_length; | |
655 name = nametab + name_offset; | |
656 | |
657 if (!(*pfn) (data, name, secoffset, secsize)) | |
658 { | |
659 *errmsg = NULL; | |
660 *err = 0; | |
661 XDELETEVEC (index); | |
662 XDELETEVEC (nametab); | |
663 XDELETEVEC (strtab); | |
664 XDELETEVEC (secdata); | |
665 return 0; | |
666 } | |
495 } | 667 } |
496 | 668 continue; |
497 name = strtab + stringoffset; | |
498 } | 669 } |
670 } | |
671 | |
672 if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) | |
673 { | |
674 memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); | |
675 namebuf[MACH_O_NAME_LEN] = '\0'; | |
676 | |
677 name = &namebuf[0]; | |
678 if (strtab != NULL && name[0] == '_' && name[1] == '_') | |
679 { | |
680 unsigned long stringoffset; | |
681 | |
682 if (sscanf (name + 2, "%08lX", &stringoffset) == 1) | |
683 { | |
684 if (stringoffset >= strtab_size) | |
685 { | |
686 *errmsg = "section name offset out of range"; | |
687 *err = 0; | |
688 XDELETEVEC (index); | |
689 XDELETEVEC (nametab); | |
690 XDELETEVEC (strtab); | |
691 XDELETEVEC (secdata); | |
692 return 0; | |
693 } | |
694 | |
695 name = strtab + stringoffset; | |
696 } | |
697 } | |
698 } | |
699 else | |
700 { | |
701 /* Otherwise, make a name like __segment,__section as per the | |
702 convention in mach-o asm. */ | |
703 name = &namebuf[0]; | |
704 memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN); | |
705 namebuf[MACH_O_NAME_LEN] = '\0'; | |
706 l = strlen (namebuf); | |
707 namebuf[l] = ','; | |
708 memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset, | |
709 MACH_O_NAME_LEN); | |
710 namebuf[l + 1 + MACH_O_NAME_LEN] = '\0'; | |
499 } | 711 } |
500 | 712 |
501 simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr, | 713 simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr, |
502 &secoffset, &secsize); | 714 &secoffset, &secsize); |
503 | 715 |
504 if (!(*pfn) (data, name, secoffset, secsize)) | 716 if (!(*pfn) (data, name, secoffset, secsize)) |
505 { | 717 { |
506 *errmsg = NULL; | 718 *errmsg = NULL; |
507 *err = 0; | 719 *err = 0; |
720 XDELETEVEC (index); | |
721 XDELETEVEC (nametab); | |
508 XDELETEVEC (strtab); | 722 XDELETEVEC (strtab); |
509 XDELETEVEC (secdata); | 723 XDELETEVEC (secdata); |
510 return 0; | 724 return 0; |
511 } | 725 } |
512 } | 726 } |
513 | 727 |
728 XDELETEVEC (index); | |
729 XDELETEVEC (nametab); | |
514 XDELETEVEC (strtab); | 730 XDELETEVEC (strtab); |
515 XDELETEVEC (secdata); | 731 XDELETEVEC (secdata); |
516 | 732 |
517 return 1; | 733 return 1; |
518 } | 734 } |
722 | 938 |
723 static int | 939 static int |
724 simple_object_mach_o_write_section_header (simple_object_write *sobj, | 940 simple_object_mach_o_write_section_header (simple_object_write *sobj, |
725 int descriptor, | 941 int descriptor, |
726 size_t sechdr_offset, | 942 size_t sechdr_offset, |
727 const char *name, size_t secaddr, | 943 const char *name, const char *segn, |
728 size_t secsize, size_t offset, | 944 size_t secaddr, size_t secsize, |
729 unsigned int align, | 945 size_t offset, unsigned int align, |
730 const char **errmsg, int *err) | 946 const char **errmsg, int *err) |
731 { | 947 { |
732 struct simple_object_mach_o_attributes *attrs = | 948 struct simple_object_mach_o_attributes *attrs = |
733 (struct simple_object_mach_o_attributes *) sobj->data; | 949 (struct simple_object_mach_o_attributes *) sobj->data; |
734 void (*set_32) (unsigned char *, unsigned int); | 950 void (*set_32) (unsigned char *, unsigned int); |
746 if (attrs->magic == MACH_O_MH_MAGIC) | 962 if (attrs->magic == MACH_O_MH_MAGIC) |
747 { | 963 { |
748 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname), | 964 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname), |
749 name, MACH_O_NAME_LEN); | 965 name, MACH_O_NAME_LEN); |
750 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname), | 966 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname), |
751 sobj->segment_name, MACH_O_NAME_LEN); | 967 segn, MACH_O_NAME_LEN); |
752 set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr); | 968 set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr); |
753 set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize); | 969 set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize); |
754 set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset); | 970 set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset); |
755 set_32 (hdr + offsetof (struct mach_o_section_32, align), align); | 971 set_32 (hdr + offsetof (struct mach_o_section_32, align), align); |
756 /* reloff left as zero. */ | 972 /* reloff left as zero. */ |
771 : simple_object_set_little_64); | 987 : simple_object_set_little_64); |
772 | 988 |
773 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname), | 989 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname), |
774 name, MACH_O_NAME_LEN); | 990 name, MACH_O_NAME_LEN); |
775 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname), | 991 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname), |
776 sobj->segment_name, MACH_O_NAME_LEN); | 992 segn, MACH_O_NAME_LEN); |
777 set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr); | 993 set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr); |
778 set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize); | 994 set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize); |
779 set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset); | 995 set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset); |
780 set_32 (hdr + offsetof (struct mach_o_section_64, align), align); | 996 set_32 (hdr + offsetof (struct mach_o_section_64, align), align); |
781 /* reloff left as zero. */ | 997 /* reloff left as zero. */ |
791 | 1007 |
792 return simple_object_internal_write (descriptor, sechdr_offset, hdr, | 1008 return simple_object_internal_write (descriptor, sechdr_offset, hdr, |
793 sechdrsize, errmsg, err); | 1009 sechdrsize, errmsg, err); |
794 } | 1010 } |
795 | 1011 |
796 /* Write out the single segment and the sections of a Mach-O file. */ | 1012 /* Write out the single (anonymous) segment containing the sections of a Mach-O |
1013 Object file. | |
1014 | |
1015 As a GNU extension to mach-o, when the caller specifies a segment name in | |
1016 sobj->segment_name, all the sections passed will be output under a single | |
1017 mach-o section header. The caller's sections are indexed within this | |
1018 'wrapper' section by a table stored in a second mach-o section. Finally, | |
1019 arbitrary length section names are permitted by the extension and these are | |
1020 stored in a table in a third mach-o section. | |
1021 | |
1022 Note that this is only likely to make any sense for the __GNU_LTO segment | |
1023 at present. | |
1024 | |
1025 If the wrapper extension is not in force, we assume that the section name | |
1026 is in the form __SEGMENT_NAME,__section_name as per Mach-O asm. */ | |
797 | 1027 |
798 static int | 1028 static int |
799 simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, | 1029 simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, |
800 size_t nsects, const char **errmsg, | 1030 size_t *nsects, const char **errmsg, |
801 int *err) | 1031 int *err) |
802 { | 1032 { |
803 struct simple_object_mach_o_attributes *attrs = | 1033 struct simple_object_mach_o_attributes *attrs = |
804 (struct simple_object_mach_o_attributes *) sobj->data; | 1034 (struct simple_object_mach_o_attributes *) sobj->data; |
805 void (*set_32) (unsigned char *, unsigned int); | 1035 void (*set_32) (unsigned char *, unsigned int); |
812 size_t secaddr; | 1042 size_t secaddr; |
813 unsigned int name_offset; | 1043 unsigned int name_offset; |
814 simple_object_write_section *section; | 1044 simple_object_write_section *section; |
815 unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; | 1045 unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; |
816 unsigned char *hdr; | 1046 unsigned char *hdr; |
1047 size_t nsects_in; | |
1048 unsigned int *index; | |
1049 char *snames; | |
1050 unsigned int sect; | |
817 | 1051 |
818 set_32 = (attrs->is_big_endian | 1052 set_32 = (attrs->is_big_endian |
819 ? simple_object_set_big_32 | 1053 ? simple_object_set_big_32 |
820 : simple_object_set_little_32); | 1054 : simple_object_set_little_32); |
821 | 1055 |
832 hdrsize = sizeof (struct mach_o_header_64); | 1066 hdrsize = sizeof (struct mach_o_header_64); |
833 seghdrsize = sizeof (struct mach_o_segment_command_64); | 1067 seghdrsize = sizeof (struct mach_o_segment_command_64); |
834 sechdrsize = sizeof (struct mach_o_section_64); | 1068 sechdrsize = sizeof (struct mach_o_section_64); |
835 } | 1069 } |
836 | 1070 |
1071 name_offset = 0; | |
1072 *nsects = nsects_in = 0; | |
1073 | |
1074 /* Count the number of sections we start with. */ | |
1075 | |
1076 for (section = sobj->sections; section != NULL; section = section->next) | |
1077 nsects_in++; | |
1078 | |
1079 if (sobj->segment_name != NULL) | |
1080 { | |
1081 /* We will only write 3 sections: wrapped data, index and names. */ | |
1082 | |
1083 *nsects = 3; | |
1084 | |
1085 /* The index has four entries per wrapped section: | |
1086 Section Offset, length, Name offset, length. | |
1087 Where the offsets are based at the start of the wrapper and name | |
1088 sections respectively. | |
1089 The values are stored as 32 bit int for both 32 and 64 bit mach-o | |
1090 since the size of a mach-o MH_OBJECT cannot exceed 4G owing to | |
1091 other constraints. */ | |
1092 | |
1093 index = XNEWVEC (unsigned int, nsects_in * 4); | |
1094 | |
1095 /* We now need to figure out the size of the names section. This just | |
1096 stores the names as null-terminated c strings, packed without any | |
1097 alignment padding. */ | |
1098 | |
1099 for (section = sobj->sections, sect = 0; section != NULL; | |
1100 section = section->next, sect++) | |
1101 { | |
1102 index[sect*4+2] = name_offset; | |
1103 index[sect*4+3] = strlen (section->name) + 1; | |
1104 name_offset += strlen (section->name) + 1; | |
1105 } | |
1106 snames = XNEWVEC (char, name_offset); | |
1107 } | |
1108 else | |
1109 { | |
1110 *nsects = nsects_in; | |
1111 index = NULL; | |
1112 snames = NULL; | |
1113 } | |
1114 | |
837 sechdr_offset = hdrsize + seghdrsize; | 1115 sechdr_offset = hdrsize + seghdrsize; |
838 cmdsize = seghdrsize + nsects * sechdrsize; | 1116 cmdsize = seghdrsize + *nsects * sechdrsize; |
839 offset = hdrsize + cmdsize; | 1117 offset = hdrsize + cmdsize; |
840 name_offset = 0; | |
841 secaddr = 0; | 1118 secaddr = 0; |
842 | 1119 |
843 for (section = sobj->sections; section != NULL; section = section->next) | 1120 for (section = sobj->sections, sect = 0; |
1121 section != NULL; section = section->next, sect++) | |
844 { | 1122 { |
845 size_t mask; | 1123 size_t mask; |
846 size_t new_offset; | 1124 size_t new_offset; |
847 size_t secsize; | 1125 size_t secsize; |
848 struct simple_object_write_section_buffer *buffer; | 1126 struct simple_object_write_section_buffer *buffer; |
849 char namebuf[MACH_O_NAME_LEN + 1]; | |
850 | 1127 |
851 mask = (1U << section->align) - 1; | 1128 mask = (1U << section->align) - 1; |
852 new_offset = offset + mask; | 1129 new_offset = offset + mask; |
853 new_offset &= ~ mask; | 1130 new_offset &= ~ mask; |
854 while (new_offset > offset) | 1131 while (new_offset > offset) |
875 buffer->size, errmsg, err)) | 1152 buffer->size, errmsg, err)) |
876 return 0; | 1153 return 0; |
877 secsize += buffer->size; | 1154 secsize += buffer->size; |
878 } | 1155 } |
879 | 1156 |
880 snprintf (namebuf, sizeof namebuf, "__%08X", name_offset); | 1157 if (sobj->segment_name != NULL) |
1158 { | |
1159 index[sect*4+0] = (unsigned int) offset; | |
1160 index[sect*4+1] = secsize; | |
1161 /* Stash the section name in our table. */ | |
1162 memcpy (snames + index[sect * 4 + 2], section->name, | |
1163 index[sect * 4 + 3]); | |
1164 } | |
1165 else | |
1166 { | |
1167 char namebuf[MACH_O_NAME_LEN + 1]; | |
1168 char segnbuf[MACH_O_NAME_LEN + 1]; | |
1169 char *comma; | |
1170 | |
1171 /* Try to extract segment,section from the input name. */ | |
1172 | |
1173 memset (namebuf, 0, sizeof namebuf); | |
1174 memset (segnbuf, 0, sizeof segnbuf); | |
1175 comma = strchr (section->name, ','); | |
1176 if (comma != NULL) | |
1177 { | |
1178 int len = comma - section->name; | |
1179 len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len; | |
1180 strncpy (namebuf, section->name, len); | |
1181 strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN); | |
1182 } | |
1183 else /* just try to copy the name, leave segment blank. */ | |
1184 strncpy (namebuf, section->name, MACH_O_NAME_LEN); | |
1185 | |
1186 if (!simple_object_mach_o_write_section_header (sobj, descriptor, | |
1187 sechdr_offset, | |
1188 namebuf, segnbuf, | |
1189 secaddr, secsize, | |
1190 offset, | |
1191 section->align, | |
1192 errmsg, err)) | |
1193 return 0; | |
1194 sechdr_offset += sechdrsize; | |
1195 } | |
1196 | |
1197 offset += secsize; | |
1198 secaddr += secsize; | |
1199 } | |
1200 | |
1201 if (sobj->segment_name != NULL) | |
1202 { | |
1203 size_t secsize; | |
1204 unsigned int i; | |
1205 | |
1206 /* Write the section header for the wrapper. */ | |
1207 /* Account for any initial aligment - which becomes the alignment for this | |
1208 created section. */ | |
1209 | |
1210 secsize = (offset - index[0]); | |
881 if (!simple_object_mach_o_write_section_header (sobj, descriptor, | 1211 if (!simple_object_mach_o_write_section_header (sobj, descriptor, |
882 sechdr_offset, namebuf, | 1212 sechdr_offset, |
883 secaddr, secsize, offset, | 1213 GNU_WRAPPER_SECTS, |
884 section->align, | 1214 sobj->segment_name, |
1215 0 /*secaddr*/, | |
1216 secsize, index[0], | |
1217 sobj->sections->align, | |
885 errmsg, err)) | 1218 errmsg, err)) |
886 return 0; | 1219 return 0; |
887 | 1220 |
1221 /* Subtract the wrapper section start from the begining of each sub | |
1222 section. */ | |
1223 | |
1224 for (i = 1; i < nsects_in; ++i) | |
1225 index[4 * i] -= index[0]; | |
1226 index[0] = 0; | |
1227 | |
888 sechdr_offset += sechdrsize; | 1228 sechdr_offset += sechdrsize; |
889 offset += secsize; | 1229 |
890 name_offset += strlen (section->name) + 1; | 1230 /* Write out the section names. |
891 secaddr += secsize; | 1231 ... the header ... |
892 } | 1232 name_offset contains the length of the section. It is not aligned. */ |
893 | 1233 |
894 /* Write out the section names. */ | 1234 if (!simple_object_mach_o_write_section_header (sobj, descriptor, |
895 | 1235 sechdr_offset, |
896 if (!simple_object_mach_o_write_section_header (sobj, descriptor, | 1236 GNU_WRAPPER_NAMES, |
897 sechdr_offset, | 1237 sobj->segment_name, |
898 GNU_SECTION_NAMES, secaddr, | 1238 0 /*secaddr*/, |
899 name_offset, offset, 0, | 1239 name_offset, |
900 errmsg, err)) | 1240 offset, |
901 return 0; | 1241 0, errmsg, err)) |
902 | 1242 return 0; |
903 for (section = sobj->sections; section != NULL; section = section->next) | 1243 |
904 { | 1244 /* ... and the content.. */ |
905 size_t namelen; | |
906 | |
907 namelen = strlen (section->name) + 1; | |
908 if (!simple_object_internal_write (descriptor, offset, | 1245 if (!simple_object_internal_write (descriptor, offset, |
909 (const unsigned char *) section->name, | 1246 (const unsigned char *) snames, |
910 namelen, errmsg, err)) | 1247 name_offset, errmsg, err)) |
911 return 0; | 1248 return 0; |
912 offset += namelen; | 1249 |
1250 sechdr_offset += sechdrsize; | |
1251 secaddr += name_offset; | |
1252 offset += name_offset; | |
1253 | |
1254 /* Now do the index, we'll align this to 4 bytes although the read code | |
1255 will handle unaligned. */ | |
1256 | |
1257 offset += 3; | |
1258 offset &= ~0x03; | |
1259 if (!simple_object_mach_o_write_section_header (sobj, descriptor, | |
1260 sechdr_offset, | |
1261 GNU_WRAPPER_INDEX, | |
1262 sobj->segment_name, | |
1263 0 /*secaddr*/, | |
1264 nsects_in * 16, | |
1265 offset, | |
1266 2, errmsg, err)) | |
1267 return 0; | |
1268 | |
1269 /* ... and the content.. */ | |
1270 if (!simple_object_internal_write (descriptor, offset, | |
1271 (const unsigned char *) index, | |
1272 nsects_in*16, errmsg, err)) | |
1273 return 0; | |
1274 | |
1275 XDELETEVEC (index); | |
1276 XDELETEVEC (snames); | |
913 } | 1277 } |
914 | 1278 |
915 /* Write out the segment header. */ | 1279 /* Write out the segment header. */ |
916 | 1280 |
917 memset (hdrbuf, 0, sizeof hdrbuf); | 1281 memset (hdrbuf, 0, sizeof hdrbuf); |
921 { | 1285 { |
922 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd), | 1286 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd), |
923 MACH_O_LC_SEGMENT); | 1287 MACH_O_LC_SEGMENT); |
924 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize), | 1288 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize), |
925 cmdsize); | 1289 cmdsize); |
926 strncpy (((char *) hdr | 1290 /* MH_OBJECTS have a single, anonymous, segment - so the segment name |
927 + offsetof (struct mach_o_segment_command_32, segname)), | 1291 is left empty. */ |
928 sobj->segment_name, MACH_O_NAME_LEN); | |
929 /* vmaddr left as zero. */ | 1292 /* vmaddr left as zero. */ |
930 /* vmsize left as zero. */ | 1293 /* vmsize left as zero. */ |
931 set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff), | 1294 set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff), |
932 hdrsize + cmdsize); | 1295 hdrsize + cmdsize); |
933 set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize), | 1296 set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize), |
934 offset - (hdrsize + cmdsize)); | 1297 offset - (hdrsize + cmdsize)); |
935 /* maxprot left as zero. */ | 1298 /* maxprot left as zero. */ |
936 /* initprot left as zero. */ | 1299 /* initprot left as zero. */ |
937 set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects), | 1300 set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects), |
938 nsects); | 1301 *nsects); |
939 /* flags left as zero. */ | 1302 /* flags left as zero. */ |
940 } | 1303 } |
941 else | 1304 else |
942 { | 1305 { |
943 #ifdef UNSIGNED_64BIT_TYPE | 1306 #ifdef UNSIGNED_64BIT_TYPE |
949 | 1312 |
950 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd), | 1313 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd), |
951 MACH_O_LC_SEGMENT); | 1314 MACH_O_LC_SEGMENT); |
952 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize), | 1315 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize), |
953 cmdsize); | 1316 cmdsize); |
954 strncpy (((char *) hdr | 1317 /* MH_OBJECTS have a single, anonymous, segment - so the segment name |
955 + offsetof (struct mach_o_segment_command_64, segname)), | 1318 is left empty. */ |
956 sobj->segment_name, MACH_O_NAME_LEN); | |
957 /* vmaddr left as zero. */ | 1319 /* vmaddr left as zero. */ |
958 /* vmsize left as zero. */ | 1320 /* vmsize left as zero. */ |
959 set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff), | 1321 set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff), |
960 hdrsize + cmdsize); | 1322 hdrsize + cmdsize); |
961 set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize), | 1323 set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize), |
962 offset - (hdrsize + cmdsize)); | 1324 offset - (hdrsize + cmdsize)); |
963 /* maxprot left as zero. */ | 1325 /* maxprot left as zero. */ |
964 /* initprot left as zero. */ | 1326 /* initprot left as zero. */ |
965 set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects), | 1327 set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects), |
966 nsects); | 1328 *nsects); |
967 /* flags left as zero. */ | 1329 /* flags left as zero. */ |
968 #endif | 1330 #endif |
969 } | 1331 } |
970 | 1332 |
971 return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize, | 1333 return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize, |
976 | 1338 |
977 static const char * | 1339 static const char * |
978 simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, | 1340 simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, |
979 int *err) | 1341 int *err) |
980 { | 1342 { |
981 size_t nsects; | 1343 size_t nsects = 0; |
982 simple_object_write_section *section; | |
983 const char *errmsg; | 1344 const char *errmsg; |
984 | 1345 |
985 /* Start at 1 for symbol_names section. */ | 1346 if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects, |
986 nsects = 1; | 1347 &errmsg, err)) |
987 for (section = sobj->sections; section != NULL; section = section->next) | 1348 return errmsg; |
988 ++nsects; | |
989 | 1349 |
990 if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, | 1350 if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, |
991 &errmsg, err)) | 1351 &errmsg, err)) |
992 return errmsg; | |
993 | |
994 if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects, | |
995 &errmsg, err)) | |
996 return errmsg; | 1352 return errmsg; |
997 | 1353 |
998 return NULL; | 1354 return NULL; |
999 } | 1355 } |
1000 | 1356 |
1016 simple_object_mach_o_release_read, | 1372 simple_object_mach_o_release_read, |
1017 simple_object_mach_o_attributes_merge, | 1373 simple_object_mach_o_attributes_merge, |
1018 simple_object_mach_o_release_attributes, | 1374 simple_object_mach_o_release_attributes, |
1019 simple_object_mach_o_start_write, | 1375 simple_object_mach_o_start_write, |
1020 simple_object_mach_o_write_to_file, | 1376 simple_object_mach_o_write_to_file, |
1021 simple_object_mach_o_release_write | 1377 simple_object_mach_o_release_write, |
1378 NULL | |
1022 }; | 1379 }; |