| @@ -107,6 +107,8 @@ struct load_command { · 106 unmodified lines |
| 107 | 107 | #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) |
| 108 | 108 | #define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) |
| 109 | 109 | #define LC_MAIN (0x28|LC_REQ_DYLD) |
| 110 | +#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD) |
| 111 | +#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD) |
| 110 | 112 | |
| 111 | 113 | typedef int vm_prot_t; |
| 112 | 114 | |
| @@ -139,6 +141,79 @@ struct section_64 { /* for 64-bit architectures */ · 26 unmodified lines |
| 139 | 141 | uint32_t reserved3; /* reserved */ |
| 140 | 142 | }; |
| 141 | 143 | |
| 144 | +enum { |
| 145 | + DYLD_CHAINED_IMPORT = 1, |
| 146 | +}; |
| 147 | + |
| 148 | +struct dyld_chained_fixups_header { |
| 149 | + uint32_t fixups_version; ///< 0 |
| 150 | + uint32_t starts_offset; ///< Offset of dyld_chained_starts_in_image. |
| 151 | + uint32_t imports_offset; ///< Offset of imports table in chain_data. |
| 152 | + uint32_t symbols_offset; ///< Offset of symbol strings in chain_data. |
| 153 | + uint32_t imports_count; ///< Number of imported symbol names. |
| 154 | + uint32_t imports_format; ///< DYLD_CHAINED_IMPORT* |
| 155 | + uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed |
| 156 | +}; |
| 157 | + |
| 158 | +struct dyld_chained_starts_in_image |
| 159 | +{ |
| 160 | + uint32_t seg_count; |
| 161 | + uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment |
| 162 | + // followed by pool of dyld_chain_starts_in_segment data |
| 163 | +}; |
| 164 | + |
| 165 | +enum { |
| 166 | + DYLD_CHAINED_PTR_64 = 2, // target is vmaddr |
| 167 | + DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset |
| 168 | +}; |
| 169 | + |
| 170 | +enum { |
| 171 | + DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups |
| 172 | +}; |
| 173 | + |
| 174 | +#define SEG_PAGE_SIZE 16384 |
| 175 | + |
| 176 | +struct dyld_chained_starts_in_segment |
| 177 | +{ |
| 178 | + uint32_t size; // size of this (amount kernel needs to copy) |
| 179 | + uint16_t page_size; // 0x1000 or 0x4000 |
| 180 | + uint16_t pointer_format; // DYLD_CHAINED_PTR_* |
| 181 | + uint64_t segment_offset; // offset in memory to start of segment |
| 182 | + uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer |
| 183 | + uint16_t page_count; // how many pages are in array |
| 184 | + uint16_t page_start[1]; // each entry is offset in each page of first element in chain |
| 185 | + // or DYLD_CHAINED_PTR_START_NONE if no fixups on page |
| 186 | +}; |
| 187 | + |
| 188 | +enum BindSpecialDylib { |
| 189 | + BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2, |
| 190 | +}; |
| 191 | + |
| 192 | +struct dyld_chained_import |
| 193 | +{ |
| 194 | + uint32_t lib_ordinal : 8, |
| 195 | + weak_import : 1, |
| 196 | + name_offset : 23; |
| 197 | +}; |
| 198 | + |
| 199 | +struct dyld_chained_ptr_64_rebase |
| 200 | +{ |
| 201 | + uint64_t target : 36, // vmaddr, 64GB max image size |
| 202 | + high8 : 8, // top 8 bits set to this after slide added |
| 203 | + reserved : 7, // all zeros |
| 204 | + next : 12, // 4-byte stride |
| 205 | + bind : 1; // == 0 |
| 206 | +}; |
| 207 | + |
| 208 | +struct dyld_chained_ptr_64_bind |
| 209 | +{ |
| 210 | + uint64_t ordinal : 24, |
| 211 | + addend : 8, // 0 thru 255 |
| 212 | + reserved : 19, // all zeros |
| 213 | + next : 12, // 4-byte stride |
| 214 | + bind : 1; // == 1 |
| 215 | +}; |
| 216 | + |
| 142 | 217 | #define S_REGULAR 0x0 |
| 143 | 218 | #define S_ZEROFILL 0x1 |
| 144 | 219 | #define S_NON_LAZY_SYMBOL_POINTERS 0x6 |
| @@ -169,6 +244,18 @@ struct dylinker_command { · 24 unmodified lines |
| 169 | 244 | lc_str name; /* dynamic linker's path name */ |
| 170 | 245 | }; |
| 171 | 246 | |
| 247 | +struct linkedit_data_command { |
| 248 | + uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, |
| 249 | + LC_FUNCTION_STARTS, LC_DATA_IN_CODE, |
| 250 | + LC_DYLIB_CODE_SIGN_DRS, |
| 251 | + LC_LINKER_OPTIMIZATION_HINT, |
| 252 | + LC_DYLD_EXPORTS_TRIE, or |
| 253 | + LC_DYLD_CHAINED_FIXUPS. */ |
| 254 | + uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ |
| 255 | + uint32_t dataoff; /* file offset of data in __LINKEDIT segment */ |
| 256 | + uint32_t datasize; /* file size of data in __LINKEDIT segment */ |
| 257 | +}; |
| 258 | + |
| 172 | 259 | struct symtab_command { |
| 173 | 260 | uint32_t cmd; /* LC_SYMTAB */ |
| 174 | 261 | uint32_t cmdsize; /* sizeof(struct symtab_command) */ |
| @@ -226,6 +313,10 @@ struct dysymtab_command { · 51 unmodified lines |
| 226 | 313 | |
| 227 | 314 | #define REBASE_TYPE_POINTER 1 |
| 228 | 315 | |
| 316 | +#define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 |
| 317 | +#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02 |
| 318 | +#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 |
| 319 | + |
| 229 | 320 | struct dyld_info_command { |
| 230 | 321 | uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ |
| 231 | 322 | uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ |
| @@ -304,26 +395,41 @@ struct macho { · 72 unmodified lines |
| 304 | 395 | } sk_to_sect[sk_last]; |
| 305 | 396 | int *elfsectomacho; |
| 306 | 397 | int *e2msym; |
| 307 | | − Section *rebase, *binding, *weak_binding, *lazy_binding, *exports; |
| 308 | | − Section *symtab, *strtab, *wdata, *indirsyms; |
| 309 | | − Section *stubs, *stub_helper, *la_symbol_ptr; |
| 310 | | − int nr_plt, n_got; |
| 311 | | − struct dyld_info_command *dyldinfo; |
| 312 | | − int stubsym, helpsym, lasym, dyld_private, dyld_stub_binder; |
| 398 | + Section *symtab, *strtab, *wdata, *indirsyms, *stubs, *exports; |
| 313 | 399 | uint32_t ilocal, iextdef, iundef; |
| 314 | | − int n_lazy_bind_rebase; |
| 315 | | − struct lazy_bind_rebase { |
| 400 | + int stubsym, n_got, nr_plt; |
| 401 | +#ifdef CONFIG_NEW_MACHO |
| 402 | + Section *chained_fixups; |
| 403 | + int n_bind; |
| 404 | + int n_bind_rebase; |
| 405 | + struct bind_rebase { |
| 406 | + int section; |
| 407 | + int bind; |
| 408 | + ElfW_Rel rel; |
| 409 | + } *bind_rebase; |
| 410 | +#else |
| 411 | + Section *rebase, *binding, *weak_binding, *lazy_binding; |
| 412 | + Section *stub_helper, *la_symbol_ptr; |
| 413 | + struct dyld_info_command *dyldinfo; |
| 414 | + int helpsym, lasym, dyld_private, dyld_stub_binder; |
| 415 | + int n_lazy_bind; |
| 416 | + struct s_lazy_bind { |
| 316 | 417 | int section; |
| 317 | | − int bind; |
| 318 | 418 | int bind_offset; |
| 319 | 419 | int la_symbol_offset; |
| 320 | 420 | ElfW_Rel rel; |
| 321 | | − } *lazy_bind_rebase; |
| 421 | + } *s_lazy_bind; |
| 422 | + int n_rebase; |
| 423 | + struct s_rebase { |
| 424 | + int section; |
| 425 | + ElfW_Rel rel; |
| 426 | + } *s_rebase; |
| 322 | 427 | int n_bind; |
| 323 | 428 | struct bind { |
| 324 | 429 | int section; |
| 325 | 430 | ElfW_Rel rel; |
| 326 | 431 | } *bind; |
| 432 | +#endif |
| 327 | 433 | }; |
| 328 | 434 | |
| 329 | 435 | #define SHT_LINKEDIT (SHT_LOOS + 42) |
| @@ -386,6 +492,7 @@ static void * add_dylib(struct macho *mo, char *name) · 56 unmodified lines |
| 386 | 492 | return lc; |
| 387 | 493 | } |
| 388 | 494 | |
| 495 | +#ifndef CONFIG_NEW_MACHO |
| 389 | 496 | static void write_uleb128(Section *section, uint64_t value) |
| 390 | 497 | { |
| 391 | 498 | do { |
| @@ -396,6 +503,7 @@ static void write_uleb128(Section *section, uint64_t value) · 4 unmodified lines |
| 396 | 503 | *ptr = byte | (value ? 0x80 : 0); |
| 397 | 504 | } while (value != 0); |
| 398 | 505 | } |
| 506 | +#endif |
| 399 | 507 | |
| 400 | 508 | static void tcc_macho_add_destructor(TCCState *s1) |
| 401 | 509 | { |
| @@ -492,6 +600,135 @@ static void tcc_macho_add_destructor(TCCState *s1) · 90 unmodified lines |
| 492 | 600 | add_array (s1, ".init_array", init_sym); |
| 493 | 601 | } |
| 494 | 602 | |
| 603 | +#ifdef CONFIG_NEW_MACHO |
| 604 | +static void bind_rebase_add(struct macho *mo, int bind, int sh_info, |
| 605 | + ElfW_Rel *rel, struct sym_attr *attr) |
| 606 | +{ |
| 607 | + mo->bind_rebase = tcc_realloc(mo->bind_rebase, (mo->n_bind_rebase + 1) * |
| 608 | + sizeof(struct bind_rebase)); |
| 609 | + mo->bind_rebase[mo->n_bind_rebase].section = sh_info; |
| 610 | + mo->bind_rebase[mo->n_bind_rebase].bind = bind; |
| 611 | + mo->bind_rebase[mo->n_bind_rebase].rel = *rel; |
| 612 | + if (attr) |
| 613 | + mo->bind_rebase[mo->n_bind_rebase].rel.r_offset = attr->got_offset; |
| 614 | + mo->n_bind_rebase++; |
| 615 | + mo->n_bind += bind; |
| 616 | +} |
| 617 | + |
| 618 | +static void check_relocs(TCCState *s1, struct macho *mo) |
| 619 | +{ |
| 620 | + Section *s; |
| 621 | + ElfW_Rel *rel; |
| 622 | + ElfW(Sym) *sym; |
| 623 | + int i, type, gotplt_entry, sym_index, for_code; |
| 624 | + int sh_num, debug; |
| 625 | + uint32_t *pi, *goti; |
| 626 | + struct sym_attr *attr; |
| 627 | + |
| 628 | + mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 629 | + goti = NULL; |
| 630 | + mo->nr_plt = mo->n_got = 0; |
| 631 | + for (i = 1; i < s1->nb_sections; i++) { |
| 632 | + s = s1->sections[i]; |
| 633 | + if (s->sh_type != SHT_RELX) |
| 634 | + continue; |
| 635 | + sh_num = s1->sections[s->sh_info]->sh_num; |
| 636 | + debug = sh_num >= s1->dwlo && sh_num < s1->dwhi; |
| 637 | + if (debug) |
| 638 | + continue; |
| 639 | + for_each_elem(s, 0, rel, ElfW_Rel) { |
| 640 | + type = ELFW(R_TYPE)(rel->r_info); |
| 641 | + gotplt_entry = gotplt_entry_type(type); |
| 642 | + for_code = code_reloc(type); |
| 643 | + /* We generate a non-lazy pointer for used undefined symbols |
| 644 | + and for defined symbols that must have a place for their |
| 645 | + address due to codegen (i.e. a reloc requiring a got slot). */ |
| 646 | + sym_index = ELFW(R_SYM)(rel->r_info); |
| 647 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 648 | + if (sym->st_shndx == SHN_UNDEF |
| 649 | + || gotplt_entry == ALWAYS_GOTPLT_ENTRY) { |
| 650 | + attr = get_sym_attr(s1, sym_index, 1); |
| 651 | + if (!attr->dyn_index) { |
| 652 | + attr->got_offset = s1->got->data_offset; |
| 653 | + attr->plt_offset = -1; |
| 654 | + attr->dyn_index = 1; /* used as flag */ |
| 655 | + section_ptr_add(s1->got, PTR_SIZE); |
| 656 | + put_elf_reloc(s1->symtab, s1->got, attr->got_offset, |
| 657 | + R_DATA_PTR, sym_index); |
| 658 | + goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti)); |
| 659 | + if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { |
| 660 | + if (sym->st_shndx == SHN_UNDEF) |
| 661 | + tcc_error("undefined local symbo: '%s'", |
| 662 | + (char *) symtab_section->link->data + sym->st_name); |
| 663 | + goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL; |
| 664 | + } else { |
| 665 | + goti[mo->n_got++] = mo->e2msym[sym_index]; |
| 666 | + if (sym->st_shndx == SHN_UNDEF |
| 667 | +#ifdef TCC_TARGET_X86_64 |
| 668 | + && type == R_X86_64_GOTPCREL |
| 669 | +#elif defined TCC_TARGET_ARM64 |
| 670 | + && type == R_AARCH64_ADR_GOT_PAGE |
| 671 | +#endif |
| 672 | + ) { |
| 673 | + bind_rebase_add(mo, 1, s1->got->reloc->sh_info, rel, attr); |
| 674 | + attr->plt_offset = 0; // ignore next bind |
| 675 | + s1->got->reloc->data_offset -= sizeof (ElfW_Rel); |
| 676 | + } |
| 677 | + if (for_code) |
| 678 | + s1->got->reloc->data_offset -= sizeof (ElfW_Rel); |
| 679 | + } |
| 680 | + } |
| 681 | + if (for_code) { |
| 682 | + if (attr->plt_offset == -1) { |
| 683 | + uint8_t *jmp; |
| 684 | + |
| 685 | + attr->plt_offset = mo->stubs->data_offset; |
| 686 | +#ifdef TCC_TARGET_X86_64 |
| 687 | + if (type != R_X86_64_PLT32) |
| 688 | + continue; |
| 689 | + jmp = section_ptr_add(mo->stubs, 6); |
| 690 | + jmp[0] = 0xff; /* jmpq *ofs(%rip) */ |
| 691 | + jmp[1] = 0x25; |
| 692 | + put_elf_reloc(s1->symtab, mo->stubs, |
| 693 | + attr->plt_offset + 2, |
| 694 | + R_X86_64_GOTPCREL, sym_index); |
| 695 | +#elif defined TCC_TARGET_ARM64 |
| 696 | + if (type != R_AARCH64_CALL26) |
| 697 | + continue; |
| 698 | + jmp = section_ptr_add(mo->stubs, 12); |
| 699 | + put_elf_reloc(s1->symtab, mo->stubs, |
| 700 | + attr->plt_offset, |
| 701 | + R_AARCH64_ADR_GOT_PAGE, sym_index); |
| 702 | + write32le(jmp, // adrp x16, #sym |
| 703 | + 0x90000010); |
| 704 | + put_elf_reloc(s1->symtab, mo->stubs, |
| 705 | + attr->plt_offset + 4, |
| 706 | + R_AARCH64_LD64_GOT_LO12_NC, sym_index); |
| 707 | + write32le(jmp + 4, // ld x16,[x16, #sym] |
| 708 | + 0xf9400210); |
| 709 | + write32le(jmp + 8, // br x16 |
| 710 | + 0xd61f0200); |
| 711 | +#endif |
| 712 | + bind_rebase_add(mo, 1, s1->got->reloc->sh_info, rel, attr); |
| 713 | + pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); |
| 714 | + *pi = mo->e2msym[sym_index]; |
| 715 | + mo->nr_plt++; |
| 716 | + } |
| 717 | + rel->r_info = ELFW(R_INFO)(mo->stubsym, type); |
| 718 | + rel->r_addend += attr->plt_offset; |
| 719 | + } |
| 720 | + } |
| 721 | + if (type == R_DATA_PTR) |
| 722 | + bind_rebase_add(mo, 0, s->sh_info, rel, NULL); |
| 723 | + } |
| 724 | + } |
| 725 | + pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi)); |
| 726 | + memcpy(pi, goti, mo->n_got * sizeof(*pi)); |
| 727 | + tcc_free(goti); |
| 728 | +} |
| 729 | + |
| 730 | +#else |
| 731 | + |
| 495 | 732 | static void check_relocs(TCCState *s1, struct macho *mo) |
| 496 | 733 | { |
| 497 | 734 | uint8_t *jmp; |
| @@ -594,9 +831,6 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 96 unmodified lines |
| 594 | 831 | } |
| 595 | 832 | if (for_code && sym->st_shndx == SHN_UNDEF) { |
| 596 | 833 | if (attr->plt_offset == -1) { |
| 597 | | − pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); |
| 598 | | − *pi = mo->e2msym[sym_index]; |
| 599 | | − mo->nr_plt++; |
| 600 | 834 | attr->plt_offset = mo->stubs->data_offset; |
| 601 | 835 | #ifdef TCC_TARGET_X86_64 |
| 602 | 836 | if (type != R_X86_64_PLT32) |
| @@ -623,7 +857,7 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 20 unmodified lines |
| 623 | 857 | mo->la_symbol_ptr->data_offset, |
| 624 | 858 | R_DATA_PTR, mo->helpsym, |
| 625 | 859 | mo->stub_helper->data_offset - 10); |
| 626 | | − jmp = section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); |
| 860 | + section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); |
| 627 | 861 | #elif defined TCC_TARGET_ARM64 |
| 628 | 862 | if (type != R_AARCH64_CALL26) |
| 629 | 863 | continue; |
| @@ -661,35 +895,36 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 31 unmodified lines |
| 661 | 895 | mo->la_symbol_ptr->data_offset, |
| 662 | 896 | R_DATA_PTR, mo->helpsym, |
| 663 | 897 | mo->stub_helper->data_offset - 12); |
| 664 | | − jmp = section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); |
| 898 | + section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); |
| 665 | 899 | #endif |
| 666 | | − mo->lazy_bind_rebase = |
| 667 | | − tcc_realloc(mo->lazy_bind_rebase, |
| 668 | | − (mo->n_lazy_bind_rebase + 1) * |
| 669 | | − sizeof(struct lazy_bind_rebase)); |
| 670 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].section = |
| 900 | + mo->s_lazy_bind = |
| 901 | + tcc_realloc(mo->s_lazy_bind, (mo->n_lazy_bind + 1) * |
| 902 | + sizeof(struct s_lazy_bind)); |
| 903 | + mo->s_lazy_bind[mo->n_lazy_bind].section = |
| 671 | 904 | mo->stub_helper->reloc->sh_info; |
| 672 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].bind = 1; |
| 673 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].bind_offset = bind_offset; |
| 674 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].la_symbol_offset = la_symbol_offset; |
| 675 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].rel = *rel; |
| 676 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].rel.r_offset = |
| 905 | + mo->s_lazy_bind[mo->n_lazy_bind].bind_offset = |
| 906 | + bind_offset; |
| 907 | + mo->s_lazy_bind[mo->n_lazy_bind].la_symbol_offset = |
| 908 | + la_symbol_offset; |
| 909 | + mo->s_lazy_bind[mo->n_lazy_bind].rel = *rel; |
| 910 | + mo->s_lazy_bind[mo->n_lazy_bind].rel.r_offset = |
| 677 | 911 | attr->plt_offset; |
| 678 | | − mo->n_lazy_bind_rebase++; |
| 912 | + mo->n_lazy_bind++; |
| 913 | + pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); |
| 914 | + *pi = mo->e2msym[sym_index]; |
| 915 | + mo->nr_plt++; |
| 679 | 916 | } |
| 680 | 917 | rel->r_info = ELFW(R_INFO)(mo->stubsym, type); |
| 681 | 918 | rel->r_addend += attr->plt_offset; |
| 682 | 919 | } |
| 683 | 920 | } |
| 684 | 921 | if (type == R_DATA_PTR) { |
| 685 | | − mo->lazy_bind_rebase = |
| 686 | | − tcc_realloc(mo->lazy_bind_rebase, |
| 687 | | − (mo->n_lazy_bind_rebase + 1) * |
| 688 | | − sizeof(struct lazy_bind_rebase)); |
| 689 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].section = s->sh_info; |
| 690 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].bind = 0; |
| 691 | | − mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].rel = *rel; |
| 692 | | − mo->n_lazy_bind_rebase++; |
| 922 | + mo->s_rebase = |
| 923 | + tcc_realloc(mo->s_rebase, (mo->n_rebase + 1) * |
| 924 | + sizeof(struct s_rebase)); |
| 925 | + mo->s_rebase[mo->n_rebase].section = s->sh_info; |
| 926 | + mo->s_rebase[mo->n_rebase].rel = *rel; |
| 927 | + mo->n_rebase++; |
| 693 | 928 | } |
| 694 | 929 | } |
| 695 | 930 | } |
| @@ -699,6 +934,7 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 3 unmodified lines |
| 699 | 934 | memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi)); |
| 700 | 935 | tcc_free(goti); |
| 701 | 936 | } |
| 937 | +#endif |
| 702 | 938 | |
| 703 | 939 | static int check_symbols(TCCState *s1, struct macho *mo) |
| 704 | 940 | { |
| @@ -865,12 +1101,16 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 160 unmodified lines |
| 865 | 1101 | /* Stub creation belongs to check_relocs, but we need to create |
| 866 | 1102 | the symbol now, so its included in the sorting. */ |
| 867 | 1103 | mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
| 868 | | − mo->stub_helper = new_section(s1, "__stub_helper", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
| 869 | 1104 | s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 870 | | − mo->la_symbol_ptr = new_section(s1, "__la_symbol_ptr", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 871 | 1105 | mo->stubsym = put_elf_sym(s1->symtab, 0, 0, |
| 872 | 1106 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| 873 | 1107 | mo->stubs->sh_num, ".__stubs"); |
| 1108 | +#ifdef CONFIG_NEW_MACHO |
| 1109 | + mo->chained_fixups = new_section(s1, "CHAINED_FIXUPS", |
| 1110 | + SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 1111 | +#else |
| 1112 | + mo->stub_helper = new_section(s1, "__stub_helper", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
| 1113 | + mo->la_symbol_ptr = new_section(s1, "__la_symbol_ptr", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 874 | 1114 | mo->helpsym = put_elf_sym(s1->symtab, 0, 0, |
| 875 | 1115 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| 876 | 1116 | mo->stub_helper->sh_num, ".__stub_helper"); |
| @@ -889,6 +1129,7 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 12 unmodified lines |
| 889 | 1129 | mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 890 | 1130 | mo->weak_binding = new_section(s1, "WEAK_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 891 | 1131 | mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 1132 | +#endif |
| 892 | 1133 | mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 893 | 1134 | |
| 894 | 1135 | mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| @@ -942,6 +1183,32 @@ const struct { · 47 unmodified lines |
| 942 | 1183 | /*[sk_linkedit] =*/ { 3, S_REGULAR, NULL }, |
| 943 | 1184 | }; |
| 944 | 1185 | |
| 1186 | +#ifdef CONFIG_NEW_MACHO |
| 1187 | +static void calc_fixup_size(TCCState *s1, struct macho *mo) |
| 1188 | +{ |
| 1189 | + int i, size; |
| 1190 | + |
| 1191 | + size = (sizeof(struct dyld_chained_fixups_header) + 7) & -8; |
| 1192 | + size += (sizeof(struct dyld_chained_starts_in_image) + (mo->nseg - 1) * sizeof(uint32_t) + 7) & -8; |
| 1193 | + for (i = 1; i < mo->nseg - 1; i++) { |
| 1194 | + int page_count = (get_segment(mo, i)->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE; |
| 1195 | + size += (sizeof(struct dyld_chained_starts_in_segment) + (page_count - 1) * sizeof(uint16_t) + 7) & -8; |
| 1196 | + } |
| 1197 | + size += mo->n_bind * sizeof (struct dyld_chained_import) + 1; |
| 1198 | + for (i = 0; i < mo->n_bind_rebase; i++) { |
| 1199 | + if (mo->bind_rebase[i].bind) { |
| 1200 | + int sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info); |
| 1201 | + ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 1202 | + const char *name = (char *) symtab_section->link->data + sym->st_name; |
| 1203 | + size += strlen(name) + 1; |
| 1204 | + } |
| 1205 | + } |
| 1206 | + size = (size + 7) & -8; |
| 1207 | + section_ptr_add(mo->chained_fixups, size); |
| 1208 | +} |
| 1209 | + |
| 1210 | +#else |
| 1211 | + |
| 945 | 1212 | static void set_segment_and_offset(struct macho *mo, addr_t addr, |
| 946 | 1213 | uint8_t *ptr, int opcode, |
| 947 | 1214 | Section *sec, addr_t offset) |
| @@ -958,49 +1225,51 @@ static void set_segment_and_offset(struct macho *mo, addr_t addr, · 10 unmodified lines |
| 958 | 1225 | write_uleb128(sec, offset - seg->vmaddr); |
| 959 | 1226 | } |
| 960 | 1227 | |
| 961 | | −static void do_bind_rebase(TCCState *s1, struct macho *mo) |
| 1228 | +static void bind_rebase(TCCState *s1, struct macho *mo) |
| 962 | 1229 | { |
| 963 | 1230 | int i; |
| 964 | 1231 | uint8_t *ptr; |
| 965 | 1232 | ElfW(Sym) *sym; |
| 966 | | − char *name; |
| 1233 | + const char *name; |
| 967 | 1234 | |
| 968 | | − for (i = 0; i < mo->n_lazy_bind_rebase; i++) { |
| 969 | | − int sym_index = ELFW(R_SYM)(mo->lazy_bind_rebase[i].rel.r_info); |
| 970 | | − Section *s = s1->sections[mo->lazy_bind_rebase[i].section]; |
| 1235 | + for (i = 0; i < mo->n_lazy_bind; i++) { |
| 1236 | + int sym_index = ELFW(R_SYM)(mo->s_lazy_bind[i].rel.r_info); |
| 971 | 1237 | |
| 972 | 1238 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 973 | 1239 | name = (char *) symtab_section->link->data + sym->st_name; |
| 974 | | − if (mo->lazy_bind_rebase[i].bind) { |
| 975 | | − write32le(mo->stub_helper->data + |
| 976 | | − mo->lazy_bind_rebase[i].bind_offset, |
| 977 | | − mo->lazy_binding->data_offset); |
| 978 | | − ptr = section_ptr_add(mo->lazy_binding, 1); |
| 979 | | − set_segment_and_offset(mo, mo->la_symbol_ptr->sh_addr, ptr, |
| 980 | | − BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 981 | | − mo->lazy_binding, |
| 982 | | − mo->la_symbol_ptr->sh_addr + |
| 983 | | − mo->lazy_bind_rebase[i].la_symbol_offset); |
| 984 | | − ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name)); |
| 985 | | − *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | |
| 986 | | − (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); |
| 987 | | − *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; |
| 988 | | − strcpy(ptr, name); |
| 989 | | − ptr += strlen(name) + 1; |
| 990 | | − *ptr++ = BIND_OPCODE_DO_BIND; |
| 991 | | − *ptr = BIND_OPCODE_DONE; |
| 992 | | − } |
| 993 | | − else { |
| 994 | | − ptr = section_ptr_add(mo->rebase, 2); |
| 995 | | − *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER; |
| 996 | | − set_segment_and_offset(mo, s->sh_addr, ptr, |
| 997 | | − REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 998 | | − mo->rebase, |
| 999 | | − mo->lazy_bind_rebase[i].rel.r_offset + |
| 1000 | | − s->sh_addr); |
| 1001 | | − ptr = section_ptr_add(mo->rebase, 1); |
| 1002 | | − *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1; |
| 1003 | | − } |
| 1240 | + write32le(mo->stub_helper->data + |
| 1241 | + mo->s_lazy_bind[i].bind_offset, |
| 1242 | + mo->lazy_binding->data_offset); |
| 1243 | + ptr = section_ptr_add(mo->lazy_binding, 1); |
| 1244 | + set_segment_and_offset(mo, mo->la_symbol_ptr->sh_addr, ptr, |
| 1245 | + BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 1246 | + mo->lazy_binding, |
| 1247 | + mo->s_lazy_bind[i].la_symbol_offset + |
| 1248 | + mo->la_symbol_ptr->sh_addr); |
| 1249 | + ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name)); |
| 1250 | + *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | |
| 1251 | + (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); |
| 1252 | + *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; |
| 1253 | + strcpy(ptr, name); |
| 1254 | + ptr += strlen(name) + 1; |
| 1255 | + *ptr++ = BIND_OPCODE_DO_BIND; |
| 1256 | + *ptr = BIND_OPCODE_DONE; |
| 1257 | + } |
| 1258 | + for (i = 0; i < mo->n_rebase; i++) { |
| 1259 | + int sym_index = ELFW(R_SYM)(mo->s_rebase[i].rel.r_info); |
| 1260 | + Section *s = s1->sections[mo->s_rebase[i].section]; |
| 1261 | + |
| 1262 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 1263 | + name = (char *) symtab_section->link->data + sym->st_name; |
| 1264 | + ptr = section_ptr_add(mo->rebase, 2); |
| 1265 | + *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER; |
| 1266 | + set_segment_and_offset(mo, s->sh_addr, ptr, |
| 1267 | + REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 1268 | + mo->rebase, |
| 1269 | + mo->s_rebase[i].rel.r_offset + |
| 1270 | + s->sh_addr); |
| 1271 | + ptr = section_ptr_add(mo->rebase, 1); |
| 1272 | + *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1; |
| 1004 | 1273 | } |
| 1005 | 1274 | for (i = 0; i < mo->n_bind; i++) { |
| 1006 | 1275 | int sym_index = ELFW(R_SYM)(mo->bind[i].rel.r_info); |
| @@ -1018,10 +1287,10 @@ static void do_bind_rebase(TCCState *s1, struct macho *mo) · 11 unmodified lines |
| 1018 | 1287 | strcpy(ptr, name); |
| 1019 | 1288 | ptr += strlen(name) + 1; |
| 1020 | 1289 | *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER; |
| 1021 | | − set_segment_and_offset(mo, s->sh_addr, ptr, |
| 1022 | | − BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 1023 | | − binding, |
| 1024 | | − mo->bind[i].rel.r_offset + s->sh_addr); |
| 1290 | + set_segment_and_offset(mo, s->sh_addr, ptr, |
| 1291 | + BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 1292 | + binding, |
| 1293 | + mo->bind[i].rel.r_offset + s->sh_addr); |
| 1025 | 1294 | ptr = section_ptr_add(binding, 1); |
| 1026 | 1295 | *ptr++ = BIND_OPCODE_DO_BIND; |
| 1027 | 1296 | } |
| @@ -1029,9 +1298,42 @@ static void do_bind_rebase(TCCState *s1, struct macho *mo) · 1 unmodified line |
| 1029 | 1298 | ptr = section_ptr_add(mo->rebase, 1); |
| 1030 | 1299 | *ptr = REBASE_OPCODE_DONE; |
| 1031 | 1300 | } |
| 1032 | | − tcc_free(mo->lazy_bind_rebase); |
| 1301 | + if (mo->binding->data_offset) { |
| 1302 | + ptr = section_ptr_add(mo->binding, 1); |
| 1303 | + *ptr = BIND_OPCODE_DONE; |
| 1304 | + } |
| 1305 | + if (mo->weak_binding->data_offset) { |
| 1306 | + ptr = section_ptr_add(mo->weak_binding, 1); |
| 1307 | + *ptr = BIND_OPCODE_DONE; |
| 1308 | + } |
| 1309 | + tcc_free(mo->s_lazy_bind); |
| 1310 | + tcc_free(mo->s_rebase); |
| 1033 | 1311 | tcc_free(mo->bind); |
| 1034 | 1312 | } |
| 1313 | +#endif |
| 1314 | + |
| 1315 | +/* FIXME */ |
| 1316 | +static void export_trie(TCCState *s1, struct macho *mo) |
| 1317 | +{ |
| 1318 | + int sym_index; |
| 1319 | + int sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));; |
| 1320 | + |
| 1321 | + for (sym_index = 1; sym_index < sym_end; ++sym_index) { |
| 1322 | + ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; |
| 1323 | + const char *name = (char*)symtab_section->link->data + sym->st_name; |
| 1324 | + |
| 1325 | + if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE && |
| 1326 | + ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL) { |
| 1327 | + int flag = EXPORT_SYMBOL_FLAGS_KIND_REGULAR; |
| 1328 | + |
| 1329 | + if (sym->st_shndx == SHN_ABS) |
| 1330 | + flag = EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE; |
| 1331 | + if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
| 1332 | + flag |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; |
| 1333 | + dprintf ("%s %d %llx\n", name, flag, sym->st_value + s1->sections[sym->st_shndx]->sh_addr); |
| 1334 | + } |
| 1335 | + } |
| 1336 | +} |
| 1035 | 1337 | |
| 1036 | 1338 | static void collect_sections(TCCState *s1, struct macho *mo) |
| 1037 | 1339 | { |
| @@ -1039,6 +1341,10 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 1 unmodified line |
| 1039 | 1341 | uint64_t curaddr, fileofs; |
| 1040 | 1342 | Section *s; |
| 1041 | 1343 | struct segment_command_64 *seg = NULL; |
| 1344 | +#ifdef CONFIG_NEW_MACHO |
| 1345 | + struct linkedit_data_command *chained_fixups_lc; |
| 1346 | + struct linkedit_data_command *export_trie_lc; |
| 1347 | +#endif |
| 1042 | 1348 | struct dylinker_command *dyldlc; |
| 1043 | 1349 | struct symtab_command *symlc; |
| 1044 | 1350 | struct dysymtab_command *dysymlc; |
| @@ -1062,6 +1368,15 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 17 unmodified lines |
| 1062 | 1368 | seg->maxprot = 7; // rwx |
| 1063 | 1369 | seg->initprot = 1; // r-- |
| 1064 | 1370 | |
| 1371 | +#ifdef CONFIG_NEW_MACHO |
| 1372 | + chained_fixups_lc = add_lc(mo, LC_DYLD_CHAINED_FIXUPS, |
| 1373 | + sizeof(struct linkedit_data_command)); |
| 1374 | + export_trie_lc = add_lc(mo, LC_DYLD_EXPORTS_TRIE, |
| 1375 | + sizeof(struct linkedit_data_command)); |
| 1376 | +#else |
| 1377 | + mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo)); |
| 1378 | +#endif |
| 1379 | + |
| 1065 | 1380 | mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep)); |
| 1066 | 1381 | mo->ep->entryoff = 4096; |
| 1067 | 1382 | |
| @@ -1071,7 +1386,6 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 3 unmodified lines |
| 1071 | 1386 | str = (char*)dyldlc + dyldlc->name; |
| 1072 | 1387 | strcpy(str, "/usr/lib/dyld"); |
| 1073 | 1388 | |
| 1074 | | − mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo)); |
| 1075 | 1389 | symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc)); |
| 1076 | 1390 | dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc)); |
| 1077 | 1391 | |
| @@ -1109,12 +1423,14 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 31 unmodified lines |
| 1109 | 1423 | case SHT_PROGBITS: |
| 1110 | 1424 | if (s == mo->stubs) |
| 1111 | 1425 | sk = sk_stubs; |
| 1426 | +#ifndef CONFIG_NEW_MACHO |
| 1112 | 1427 | else if (s == mo->stub_helper) |
| 1113 | 1428 | sk = sk_stub_helper; |
| 1114 | | − else if (s == s1->got) |
| 1115 | | − sk = sk_nl_ptr; |
| 1116 | 1429 | else if (s == mo->la_symbol_ptr) |
| 1117 | 1430 | sk = sk_la_ptr; |
| 1431 | +#endif |
| 1432 | + else if (s == s1->got) |
| 1433 | + sk = sk_nl_ptr; |
| 1118 | 1434 | else if (s == stab_section) |
| 1119 | 1435 | sk = sk_stab; |
| 1120 | 1436 | else if (s == dwarf_info_section) |
| @@ -1150,15 +1466,23 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 29 unmodified lines |
| 1150 | 1466 | mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections); |
| 1151 | 1467 | for (sk = sk_unknown; sk < sk_last; sk++) { |
| 1152 | 1468 | struct section_64 *sec = NULL; |
| 1153 | | −#define SEG_PAGE_SIZE 16384 |
| 1154 | | − if (sk == sk_linkedit) |
| 1155 | | − do_bind_rebase(s1, mo); |
| 1156 | 1469 | if (seg) { |
| 1157 | 1470 | seg->vmsize = (curaddr - seg->vmaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 1158 | 1471 | seg->filesize = (fileofs - seg->fileoff + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 1159 | 1472 | curaddr = seg->vmaddr + seg->vmsize; |
| 1160 | 1473 | fileofs = seg->fileoff + seg->filesize; |
| 1161 | 1474 | } |
| 1475 | +#ifdef CONFIG_NEW_MACHO |
| 1476 | + if (sk == sk_linkedit) { |
| 1477 | + calc_fixup_size(s1, mo); |
| 1478 | + export_trie(s1, mo); |
| 1479 | + } |
| 1480 | +#else |
| 1481 | + if (sk == sk_linkedit) { |
| 1482 | + bind_rebase(s1, mo); |
| 1483 | + export_trie(s1, mo); |
| 1484 | + } |
| 1485 | +#endif |
| 1162 | 1486 | if (skinfo[sk].seg && mo->sk_to_sect[sk].s) { |
| 1163 | 1487 | uint64_t al = 0; |
| 1164 | 1488 | int si; |
| @@ -1178,14 +1502,23 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 13 unmodified lines |
| 1178 | 1502 | #endif |
| 1179 | 1503 | if (sk == sk_nl_ptr) |
| 1180 | 1504 | sec->reserved1 = mo->nr_plt; |
| 1505 | +#ifndef CONFIG_NEW_MACHO |
| 1181 | 1506 | if (sk == sk_la_ptr) |
| 1182 | 1507 | sec->reserved1 = mo->nr_plt + mo->n_got; |
| 1508 | +#endif |
| 1183 | 1509 | } |
| 1184 | 1510 | if (seg->vmaddr == -1) { |
| 1511 | +#ifdef CONFIG_NEW_MACHO |
| 1512 | + curaddr = (curaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 1513 | + seg->vmaddr = curaddr; |
| 1514 | + fileofs = (fileofs + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 1515 | + seg->fileoff = fileofs; |
| 1516 | +#else |
| 1185 | 1517 | curaddr = (curaddr + 4095) & -4096; |
| 1186 | 1518 | seg->vmaddr = curaddr; |
| 1187 | 1519 | fileofs = (fileofs + 4095) & -4096; |
| 1188 | 1520 | seg->fileoff = fileofs; |
| 1521 | +#endif |
| 1189 | 1522 | } |
| 1190 | 1523 | |
| 1191 | 1524 | for (s = mo->sk_to_sect[sk].s; s; s = s->prev) { |
| @@ -1266,6 +1599,16 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 74 unmodified lines |
| 1266 | 1599 | dysymlc->indirectsymoff = mo->indirsyms->sh_offset; |
| 1267 | 1600 | dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t); |
| 1268 | 1601 | |
| 1602 | +#ifdef CONFIG_NEW_MACHO |
| 1603 | + if (mo->chained_fixups->data_offset) { |
| 1604 | + chained_fixups_lc->dataoff = mo->chained_fixups->sh_offset; |
| 1605 | + chained_fixups_lc->datasize = mo->chained_fixups->data_offset; |
| 1606 | + } |
| 1607 | + if (mo->exports->data_offset) { |
| 1608 | + export_trie_lc->dataoff = mo->exports->sh_offset; |
| 1609 | + export_trie_lc->datasize = mo->exports->data_offset; |
| 1610 | + } |
| 1611 | +#else |
| 1269 | 1612 | if (mo->rebase->data_offset) { |
| 1270 | 1613 | mo->dyldinfo->rebase_off = mo->rebase->sh_offset; |
| 1271 | 1614 | mo->dyldinfo->rebase_size = mo->rebase->data_offset; |
| @@ -1286,6 +1629,7 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 14 unmodified lines |
| 1286 | 1629 | mo->dyldinfo->export_off = mo->exports->sh_offset; |
| 1287 | 1630 | mo->dyldinfo->export_size = mo->exports->data_offset; |
| 1288 | 1631 | } |
| 1632 | +#endif |
| 1289 | 1633 | } |
| 1290 | 1634 | |
| 1291 | 1635 | static void macho_write(TCCState *s1, struct macho *mo, FILE *fp) |
| @@ -1333,6 +1677,170 @@ static void macho_write(TCCState *s1, struct macho *mo, FILE *fp) · 41 unmodified lines |
| 1333 | 1677 | } |
| 1334 | 1678 | } |
| 1335 | 1679 | |
| 1680 | +#ifdef CONFIG_NEW_MACHO |
| 1681 | +static int bind_rebase_cmp(const void *_a, const void *_b, void *arg) |
| 1682 | +{ |
| 1683 | + TCCState *s1 = arg; |
| 1684 | + struct bind_rebase *a = (struct bind_rebase *) _a; |
| 1685 | + struct bind_rebase *b = (struct bind_rebase *) _b; |
| 1686 | + addr_t aa = s1->sections[a->section]->sh_addr + a->rel.r_offset; |
| 1687 | + addr_t ab = s1->sections[b->section]->sh_addr + b->rel.r_offset; |
| 1688 | + |
| 1689 | + return aa > ab ? 1 : aa < ab ? -1 : 0; |
| 1690 | +} |
| 1691 | + |
| 1692 | +ST_FUNC void bind_rebase_import(TCCState *s1, struct macho *mo) |
| 1693 | +{ |
| 1694 | + int i, j, k, bind_index, size, page_count, sym_index; |
| 1695 | + const char *name; |
| 1696 | + ElfW_Rel rel; |
| 1697 | + ElfW(Sym) *sym; |
| 1698 | + unsigned char *data = mo->chained_fixups->data; |
| 1699 | + struct segment_command_64 *seg; |
| 1700 | + struct dyld_chained_fixups_header *header; |
| 1701 | + struct dyld_chained_starts_in_image *image; |
| 1702 | + struct dyld_chained_starts_in_segment *segment; |
| 1703 | + struct dyld_chained_import *import; |
| 1704 | + |
| 1705 | + tcc_qsort(mo->bind_rebase, mo->n_bind_rebase, sizeof(struct bind_rebase), |
| 1706 | + bind_rebase_cmp, s1); |
| 1707 | + for (i = 0; i < mo->n_bind_rebase - 1; i++) |
| 1708 | + if (mo->bind_rebase[i].section == mo->bind_rebase[i + 1].section && |
| 1709 | + mo->bind_rebase[i].rel.r_offset == mo->bind_rebase[i + 1].rel.r_offset) { |
| 1710 | + sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info); |
| 1711 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 1712 | + name = (char *) symtab_section->link->data + sym->st_name; |
| 1713 | + tcc_error("Overlap bind/rebase %s:%s", |
| 1714 | + s1->sections[mo->bind_rebase[i].section]->name, name); |
| 1715 | + } |
| 1716 | + header = (struct dyld_chained_fixups_header *) data; |
| 1717 | + data += (sizeof(struct dyld_chained_fixups_header) + 7) & -8; |
| 1718 | + header->starts_offset = data - mo->chained_fixups->data; |
| 1719 | + header->imports_count = mo->n_bind; |
| 1720 | + header->imports_format = DYLD_CHAINED_IMPORT; |
| 1721 | + header->symbols_format = 0; |
| 1722 | + size = sizeof(struct dyld_chained_starts_in_image) + |
| 1723 | + (mo->nseg - 1) * sizeof(uint32_t); |
| 1724 | + image = (struct dyld_chained_starts_in_image *) data; |
| 1725 | + data += (size + 7) & -8; |
| 1726 | + image->seg_count = mo->nseg; |
| 1727 | + for (i = 1; i < mo->nseg - 1; i++) { |
| 1728 | + image->seg_info_offset[i] = (data - mo->chained_fixups->data) - |
| 1729 | + header->starts_offset; |
| 1730 | + seg = get_segment(mo, i); |
| 1731 | + page_count = (seg->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE; |
| 1732 | + size = sizeof(struct dyld_chained_starts_in_segment) + |
| 1733 | + (page_count - 1) * sizeof(uint16_t); |
| 1734 | + segment = (struct dyld_chained_starts_in_segment *) data; |
| 1735 | + data += (size + 7) & -8; |
| 1736 | + segment->size = size; |
| 1737 | + segment->page_size = SEG_PAGE_SIZE; |
| 1738 | +#if 1 |
| 1739 | +#define PTR_64_OFFSET 0 |
| 1740 | +#define PTR_64_MASK 0x7FFFFFFFFFFULL |
| 1741 | + segment->pointer_format = DYLD_CHAINED_PTR_64; |
| 1742 | +#else |
| 1743 | +#define PTR_64_OFFSET 0x100000000ULL |
| 1744 | +#define PTR_64_MASK 0xFFFFFFFFFFFFFFULL |
| 1745 | + segment->pointer_format = DYLD_CHAINED_PTR_64_OFFSET; |
| 1746 | +#endif |
| 1747 | + segment->segment_offset = seg->fileoff; |
| 1748 | + segment->max_valid_pointer = 0; |
| 1749 | + segment->page_count = page_count; |
| 1750 | + // add bind/rebase |
| 1751 | + for (j = 0; j < page_count; j++) { |
| 1752 | + uint64_t start = seg->vmaddr + j * SEG_PAGE_SIZE; |
| 1753 | + uint64_t end = start + SEG_PAGE_SIZE; |
| 1754 | + void *last; |
| 1755 | + addr_t last_o = 0; |
| 1756 | + uint64_t cur_o, cur; |
| 1757 | + struct dyld_chained_ptr_64_rebase *rebase; |
| 1758 | + struct dyld_chained_ptr_64_bind *bind; |
| 1759 | + Section *s; |
| 1760 | + |
| 1761 | + segment->page_start[j] = DYLD_CHAINED_PTR_START_NONE; |
| 1762 | + for (k = 0, bind_index = 0; k < mo->n_bind_rebase; k++) { |
| 1763 | + uint64_t addr; |
| 1764 | + |
| 1765 | + s = s1->sections[mo->bind_rebase[k].section]; |
| 1766 | + rel = mo->bind_rebase[k].rel; |
| 1767 | + if ((rel.r_offset & 3) || |
| 1768 | + (rel.r_offset & (SEG_PAGE_SIZE - 1)) > |
| 1769 | + SEG_PAGE_SIZE - PTR_SIZE) |
| 1770 | + tcc_error("Illegal rel_offset %s %lld", |
| 1771 | + s->name, (long long)rel.r_offset); |
| 1772 | + addr = s->sh_addr + rel.r_offset; |
| 1773 | + if (addr >= start && addr < end) { |
| 1774 | + cur_o = addr - start; |
| 1775 | + if (mo->bind_rebase[k].bind) { |
| 1776 | + if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE) |
| 1777 | + segment->page_start[j] = cur_o; |
| 1778 | + else { |
| 1779 | + bind = (struct dyld_chained_ptr_64_bind *) last; |
| 1780 | + bind->next = (cur_o - last_o) / 4; |
| 1781 | + } |
| 1782 | + bind = (struct dyld_chained_ptr_64_bind *) |
| 1783 | + (s->data + rel.r_offset); |
| 1784 | + last = bind; |
| 1785 | + last_o = cur_o; |
| 1786 | + bind->ordinal = bind_index; |
| 1787 | + bind->addend = 0; |
| 1788 | + bind->reserved = 0; |
| 1789 | + bind->next = 0; |
| 1790 | + bind->bind = 1; |
| 1791 | + } |
| 1792 | + else { |
| 1793 | + if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE) |
| 1794 | + segment->page_start[j] = cur_o; |
| 1795 | + else { |
| 1796 | + rebase = (struct dyld_chained_ptr_64_rebase *) last; |
| 1797 | + rebase->next = (cur_o - last_o) / 4; |
| 1798 | + } |
| 1799 | + rebase = (struct dyld_chained_ptr_64_rebase *) |
| 1800 | + (s->data + rel.r_offset); |
| 1801 | + last = rebase; |
| 1802 | + last_o = cur_o; |
| 1803 | + cur = (*(uint64_t *) (s->data + rel.r_offset)) - |
| 1804 | + PTR_64_OFFSET; |
| 1805 | + rebase->target = cur & PTR_64_MASK; |
| 1806 | + rebase->high8 = cur >> (64 - 8); |
| 1807 | + if (cur != ((uint64_t)rebase->high8 << (64 - 8)) + rebase->target) |
| 1808 | + tcc_error("rebase error"); |
| 1809 | + rebase->reserved = 0; |
| 1810 | + rebase->next = 0; |
| 1811 | + rebase->bind = 0; |
| 1812 | + } |
| 1813 | + } |
| 1814 | + bind_index += mo->bind_rebase[k].bind; |
| 1815 | + } |
| 1816 | + } |
| 1817 | + } |
| 1818 | + // add imports |
| 1819 | + header->imports_offset = data - mo->chained_fixups->data; |
| 1820 | + import = (struct dyld_chained_import *) data; |
| 1821 | + data += mo->n_bind * sizeof (struct dyld_chained_import); |
| 1822 | + header->symbols_offset = data - mo->chained_fixups->data; |
| 1823 | + data++; |
| 1824 | + for (i = 0, bind_index = 0; i < mo->n_bind_rebase; i++) { |
| 1825 | + if (mo->bind_rebase[i].bind) { |
| 1826 | + import[bind_index].lib_ordinal = |
| 1827 | + BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xffu; |
| 1828 | + import[bind_index].name_offset = |
| 1829 | + (data - mo->chained_fixups->data) - header->symbols_offset; |
| 1830 | + sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info); |
| 1831 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 1832 | + import[bind_index].weak_import = |
| 1833 | + ELFW(ST_BIND)(sym->st_info) == STB_WEAK; |
| 1834 | + name = (char *) symtab_section->link->data + sym->st_name; |
| 1835 | + strcpy(data, name); |
| 1836 | + data += strlen(name) + 1; |
| 1837 | + bind_index++; |
| 1838 | + } |
| 1839 | + } |
| 1840 | + tcc_free(mo->bind_rebase); |
| 1841 | +} |
| 1842 | +#endif |
| 1843 | + |
| 1336 | 1844 | ST_FUNC int macho_output_file(TCCState *s1, const char *filename) |
| 1337 | 1845 | { |
| 1338 | 1846 | int fd, mode, file_type; |
| @@ -1370,6 +1878,9 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) · 31 unmodified lines |
| 1370 | 1878 | if (s1->nb_errors) |
| 1371 | 1879 | goto do_ret; |
| 1372 | 1880 | relocate_sections(s1); |
| 1881 | +#ifdef CONFIG_NEW_MACHO |
| 1882 | + bind_rebase_import(s1, &mo); |
| 1883 | +#endif |
| 1373 | 1884 | convert_symbols(s1, &mo); |
| 1374 | 1885 | macho_write(s1, &mo, fp); |
| 1375 | 1886 | } |