| @@ -107,6 +107,8 @@ struct load_command { · 106 unmodified lines |
| 107 | #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) | 107 | #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) |
| 108 | #define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) | 108 | #define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) |
| 109 | #define LC_MAIN (0x28|LC_REQ_DYLD) | 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 | typedef int vm_prot_t; | 113 | typedef int vm_prot_t; |
| 112 | | 114 | |
| @@ -139,6 +141,79 @@ struct section_64 { /* for 64-bit architectures */ · 26 unmodified lines |
| 139 | uint32_t reserved3; /* reserved */ | 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 | #define S_REGULAR 0x0 | 217 | #define S_REGULAR 0x0 |
| 143 | #define S_ZEROFILL 0x1 | 218 | #define S_ZEROFILL 0x1 |
| 144 | #define S_NON_LAZY_SYMBOL_POINTERS 0x6 | 219 | #define S_NON_LAZY_SYMBOL_POINTERS 0x6 |
| @@ -169,6 +244,18 @@ struct dylinker_command { · 24 unmodified lines |
| 169 | lc_str name; /* dynamic linker's path name */ | 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 | struct symtab_command { | 259 | struct symtab_command { |
| 173 | uint32_t cmd; /* LC_SYMTAB */ | 260 | uint32_t cmd; /* LC_SYMTAB */ |
| 174 | uint32_t cmdsize; /* sizeof(struct symtab_command) */ | 261 | uint32_t cmdsize; /* sizeof(struct symtab_command) */ |
| @@ -226,6 +313,10 @@ struct dysymtab_command { · 51 unmodified lines |
| 226 | | 313 | |
| 227 | #define REBASE_TYPE_POINTER 1 | 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 | struct dyld_info_command { | 320 | struct dyld_info_command { |
| 230 | uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ | 321 | uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ |
| 231 | uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ | 322 | uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ |
| @@ -304,26 +395,41 @@ struct macho { · 72 unmodified lines |
| 304 | } sk_to_sect[sk_last]; | 395 | } sk_to_sect[sk_last]; |
| 305 | int *elfsectomacho; | 396 | int *elfsectomacho; |
| 306 | int *e2msym; | 397 | int *e2msym; |
| 307 | Section *rebase, *binding, *weak_binding, *lazy_binding, *exports; | 398 | Section *symtab, *strtab, *wdata, *indirsyms, *stubs, *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; | | |
| 313 | uint32_t ilocal, iextdef, iundef; | 399 | uint32_t ilocal, iextdef, iundef; |
| 314 | int n_lazy_bind_rebase; | 400 | int stubsym, n_got, nr_plt; |
| 315 | struct lazy_bind_rebase { | 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 | int section; | 417 | int section; |
| 317 | int bind; | | |
| 318 | int bind_offset; | 418 | int bind_offset; |
| 319 | int la_symbol_offset; | 419 | int la_symbol_offset; |
| 320 | ElfW_Rel rel; | 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 | int n_bind; | 427 | int n_bind; |
| 323 | struct bind { | 428 | struct bind { |
| 324 | int section; | 429 | int section; |
| 325 | ElfW_Rel rel; | 430 | ElfW_Rel rel; |
| 326 | } *bind; | 431 | } *bind; |
| | 432 | #endif |
| 327 | }; | 433 | }; |
| 328 | | 434 | |
| 329 | #define SHT_LINKEDIT (SHT_LOOS + 42) | 435 | #define SHT_LINKEDIT (SHT_LOOS + 42) |
| @@ -386,6 +492,7 @@ static void * add_dylib(struct macho *mo, char *name) · 56 unmodified lines |
| 386 | return lc; | 492 | return lc; |
| 387 | } | 493 | } |
| 388 | | 494 | |
| | 495 | #ifndef CONFIG_NEW_MACHO |
| 389 | static void write_uleb128(Section *section, uint64_t value) | 496 | static void write_uleb128(Section *section, uint64_t value) |
| 390 | { | 497 | { |
| 391 | do { | 498 | do { |
| @@ -396,6 +503,7 @@ static void write_uleb128(Section *section, uint64_t value) · 4 unmodified lines |
| 396 | *ptr = byte | (value ? 0x80 : 0); | 503 | *ptr = byte | (value ? 0x80 : 0); |
| 397 | } while (value != 0); | 504 | } while (value != 0); |
| 398 | } | 505 | } |
| | 506 | #endif |
| 399 | | 507 | |
| 400 | static void tcc_macho_add_destructor(TCCState *s1) | 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 | add_array (s1, ".init_array", init_sym); | 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 | static void check_relocs(TCCState *s1, struct macho *mo) | 732 | static void check_relocs(TCCState *s1, struct macho *mo) |
| 496 | { | 733 | { |
| 497 | uint8_t *jmp; | 734 | uint8_t *jmp; |
| @@ -594,9 +831,6 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 96 unmodified lines |
| 594 | } | 831 | } |
| 595 | if (for_code && sym->st_shndx == SHN_UNDEF) { | 832 | if (for_code && sym->st_shndx == SHN_UNDEF) { |
| 596 | if (attr->plt_offset == -1) { | 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 | attr->plt_offset = mo->stubs->data_offset; | 834 | attr->plt_offset = mo->stubs->data_offset; |
| 601 | #ifdef TCC_TARGET_X86_64 | 835 | #ifdef TCC_TARGET_X86_64 |
| 602 | if (type != R_X86_64_PLT32) | 836 | if (type != R_X86_64_PLT32) |
| @@ -623,7 +857,7 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 20 unmodified lines |
| 623 | mo->la_symbol_ptr->data_offset, | 857 | mo->la_symbol_ptr->data_offset, |
| 624 | R_DATA_PTR, mo->helpsym, | 858 | R_DATA_PTR, mo->helpsym, |
| 625 | mo->stub_helper->data_offset - 10); | 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 | #elif defined TCC_TARGET_ARM64 | 861 | #elif defined TCC_TARGET_ARM64 |
| 628 | if (type != R_AARCH64_CALL26) | 862 | if (type != R_AARCH64_CALL26) |
| 629 | continue; | 863 | continue; |
| @@ -661,35 +895,36 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 31 unmodified lines |
| 661 | mo->la_symbol_ptr->data_offset, | 895 | mo->la_symbol_ptr->data_offset, |
| 662 | R_DATA_PTR, mo->helpsym, | 896 | R_DATA_PTR, mo->helpsym, |
| 663 | mo->stub_helper->data_offset - 12); | 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 | #endif | 899 | #endif |
| 666 | mo->lazy_bind_rebase = | 900 | mo->s_lazy_bind = |
| 667 | tcc_realloc(mo->lazy_bind_rebase, | 901 | tcc_realloc(mo->s_lazy_bind, (mo->n_lazy_bind + 1) * |
| 668 | (mo->n_lazy_bind_rebase + 1) * | 902 | sizeof(struct s_lazy_bind)); |
| 669 | sizeof(struct lazy_bind_rebase)); | 903 | mo->s_lazy_bind[mo->n_lazy_bind].section = |
| 670 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].section = | | |
| 671 | mo->stub_helper->reloc->sh_info; | 904 | mo->stub_helper->reloc->sh_info; |
| 672 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].bind = 1; | 905 | mo->s_lazy_bind[mo->n_lazy_bind].bind_offset = |
| 673 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].bind_offset = bind_offset; | 906 | bind_offset; |
| 674 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].la_symbol_offset = la_symbol_offset; | 907 | mo->s_lazy_bind[mo->n_lazy_bind].la_symbol_offset = |
| 675 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].rel = *rel; | 908 | la_symbol_offset; |
| 676 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].rel.r_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 | attr->plt_offset; | 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 | rel->r_info = ELFW(R_INFO)(mo->stubsym, type); | 917 | rel->r_info = ELFW(R_INFO)(mo->stubsym, type); |
| 681 | rel->r_addend += attr->plt_offset; | 918 | rel->r_addend += attr->plt_offset; |
| 682 | } | 919 | } |
| 683 | } | 920 | } |
| 684 | if (type == R_DATA_PTR) { | 921 | if (type == R_DATA_PTR) { |
| 685 | mo->lazy_bind_rebase = | 922 | mo->s_rebase = |
| 686 | tcc_realloc(mo->lazy_bind_rebase, | 923 | tcc_realloc(mo->s_rebase, (mo->n_rebase + 1) * |
| 687 | (mo->n_lazy_bind_rebase + 1) * | 924 | sizeof(struct s_rebase)); |
| 688 | sizeof(struct lazy_bind_rebase)); | 925 | mo->s_rebase[mo->n_rebase].section = s->sh_info; |
| 689 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].section = s->sh_info; | 926 | mo->s_rebase[mo->n_rebase].rel = *rel; |
| 690 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].bind = 0; | 927 | mo->n_rebase++; |
| 691 | mo->lazy_bind_rebase[mo->n_lazy_bind_rebase].rel = *rel; | | |
| 692 | mo->n_lazy_bind_rebase++; | | |
| 693 | } | 928 | } |
| 694 | } | 929 | } |
| 695 | } | 930 | } |
| @@ -699,6 +934,7 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 3 unmodified lines |
| 699 | memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi)); | 934 | memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi)); |
| 700 | tcc_free(goti); | 935 | tcc_free(goti); |
| 701 | } | 936 | } |
| | 937 | #endif |
| 702 | | 938 | |
| 703 | static int check_symbols(TCCState *s1, struct macho *mo) | 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 | /* Stub creation belongs to check_relocs, but we need to create | 1101 | /* Stub creation belongs to check_relocs, but we need to create |
| 866 | the symbol now, so its included in the sorting. */ | 1102 | the symbol now, so its included in the sorting. */ |
| 867 | mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); | 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 | s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); | 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 | mo->stubsym = put_elf_sym(s1->symtab, 0, 0, | 1105 | mo->stubsym = put_elf_sym(s1->symtab, 0, 0, |
| 872 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, | 1106 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| 873 | mo->stubs->sh_num, ".__stubs"); | 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 | mo->helpsym = put_elf_sym(s1->symtab, 0, 0, | 1114 | mo->helpsym = put_elf_sym(s1->symtab, 0, 0, |
| 875 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, | 1115 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| 876 | mo->stub_helper->sh_num, ".__stub_helper"); | 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 | mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 1129 | mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 890 | mo->weak_binding = new_section(s1, "WEAK_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 1130 | mo->weak_binding = new_section(s1, "WEAK_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 891 | mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 1131 | mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| | 1132 | #endif |
| 892 | mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 1133 | mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 893 | | 1134 | |
| 894 | mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 1135 | mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| @@ -942,6 +1183,32 @@ const struct { · 47 unmodified lines |
| 942 | /*[sk_linkedit] =*/ { 3, S_REGULAR, NULL }, | 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 | static void set_segment_and_offset(struct macho *mo, addr_t addr, | 1212 | static void set_segment_and_offset(struct macho *mo, addr_t addr, |
| 946 | uint8_t *ptr, int opcode, | 1213 | uint8_t *ptr, int opcode, |
| 947 | Section *sec, addr_t offset) | 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 | write_uleb128(sec, offset - seg->vmaddr); | 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 | int i; | 1230 | int i; |
| 964 | uint8_t *ptr; | 1231 | uint8_t *ptr; |
| 965 | ElfW(Sym) *sym; | 1232 | ElfW(Sym) *sym; |
| 966 | char *name; | 1233 | const char *name; |
| 967 | | 1234 | |
| 968 | for (i = 0; i < mo->n_lazy_bind_rebase; i++) { | 1235 | for (i = 0; i < mo->n_lazy_bind; i++) { |
| 969 | int sym_index = ELFW(R_SYM)(mo->lazy_bind_rebase[i].rel.r_info); | 1236 | int sym_index = ELFW(R_SYM)(mo->s_lazy_bind[i].rel.r_info); |
| 970 | Section *s = s1->sections[mo->lazy_bind_rebase[i].section]; | | |
| 971 | | 1237 | |
| 972 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | 1238 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 973 | name = (char *) symtab_section->link->data + sym->st_name; | 1239 | name = (char *) symtab_section->link->data + sym->st_name; |
| 974 | if (mo->lazy_bind_rebase[i].bind) { | 1240 | write32le(mo->stub_helper->data + |
| 975 | write32le(mo->stub_helper->data + | 1241 | mo->s_lazy_bind[i].bind_offset, |
| 976 | mo->lazy_bind_rebase[i].bind_offset, | 1242 | mo->lazy_binding->data_offset); |
| 977 | mo->lazy_binding->data_offset); | 1243 | ptr = section_ptr_add(mo->lazy_binding, 1); |
| 978 | ptr = section_ptr_add(mo->lazy_binding, 1); | 1244 | set_segment_and_offset(mo, mo->la_symbol_ptr->sh_addr, ptr, |
| 979 | set_segment_and_offset(mo, mo->la_symbol_ptr->sh_addr, ptr, | 1245 | BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 980 | BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, | 1246 | mo->lazy_binding, |
| 981 | mo->lazy_binding, | 1247 | mo->s_lazy_bind[i].la_symbol_offset + |
| 982 | mo->la_symbol_ptr->sh_addr + | 1248 | mo->la_symbol_ptr->sh_addr); |
| 983 | mo->lazy_bind_rebase[i].la_symbol_offset); | 1249 | ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name)); |
| 984 | ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name)); | 1250 | *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | |
| 985 | *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | | 1251 | (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); |
| 986 | (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); | 1252 | *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; |
| 987 | *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; | 1253 | strcpy(ptr, name); |
| 988 | strcpy(ptr, name); | 1254 | ptr += strlen(name) + 1; |
| 989 | ptr += strlen(name) + 1; | 1255 | *ptr++ = BIND_OPCODE_DO_BIND; |
| 990 | *ptr++ = BIND_OPCODE_DO_BIND; | 1256 | *ptr = BIND_OPCODE_DONE; |
| 991 | *ptr = BIND_OPCODE_DONE; | 1257 | } |
| 992 | } | 1258 | for (i = 0; i < mo->n_rebase; i++) { |
| 993 | else { | 1259 | int sym_index = ELFW(R_SYM)(mo->s_rebase[i].rel.r_info); |
| 994 | ptr = section_ptr_add(mo->rebase, 2); | 1260 | Section *s = s1->sections[mo->s_rebase[i].section]; |
| 995 | *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER; | 1261 | |
| 996 | set_segment_and_offset(mo, s->sh_addr, ptr, | 1262 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 997 | REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, | 1263 | name = (char *) symtab_section->link->data + sym->st_name; |
| 998 | mo->rebase, | 1264 | ptr = section_ptr_add(mo->rebase, 2); |
| 999 | mo->lazy_bind_rebase[i].rel.r_offset + | 1265 | *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER; |
| 1000 | s->sh_addr); | 1266 | set_segment_and_offset(mo, s->sh_addr, ptr, |
| 1001 | ptr = section_ptr_add(mo->rebase, 1); | 1267 | REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 1002 | *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1; | 1268 | mo->rebase, |
| 1003 | } | 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 | for (i = 0; i < mo->n_bind; i++) { | 1274 | for (i = 0; i < mo->n_bind; i++) { |
| 1006 | int sym_index = ELFW(R_SYM)(mo->bind[i].rel.r_info); | 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 | strcpy(ptr, name); | 1287 | strcpy(ptr, name); |
| 1019 | ptr += strlen(name) + 1; | 1288 | ptr += strlen(name) + 1; |
| 1020 | *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER; | 1289 | *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER; |
| 1021 | set_segment_and_offset(mo, s->sh_addr, ptr, | 1290 | set_segment_and_offset(mo, s->sh_addr, ptr, |
| 1022 | BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, | 1291 | BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| 1023 | binding, | 1292 | binding, |
| 1024 | mo->bind[i].rel.r_offset + s->sh_addr); | 1293 | mo->bind[i].rel.r_offset + s->sh_addr); |
| 1025 | ptr = section_ptr_add(binding, 1); | 1294 | ptr = section_ptr_add(binding, 1); |
| 1026 | *ptr++ = BIND_OPCODE_DO_BIND; | 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 | ptr = section_ptr_add(mo->rebase, 1); | 1298 | ptr = section_ptr_add(mo->rebase, 1); |
| 1030 | *ptr = REBASE_OPCODE_DONE; | 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 | tcc_free(mo->bind); | 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 | static void collect_sections(TCCState *s1, struct macho *mo) | 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 | uint64_t curaddr, fileofs; | 1341 | uint64_t curaddr, fileofs; |
| 1040 | Section *s; | 1342 | Section *s; |
| 1041 | struct segment_command_64 *seg = NULL; | 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 | struct dylinker_command *dyldlc; | 1348 | struct dylinker_command *dyldlc; |
| 1043 | struct symtab_command *symlc; | 1349 | struct symtab_command *symlc; |
| 1044 | struct dysymtab_command *dysymlc; | 1350 | struct dysymtab_command *dysymlc; |
| @@ -1062,6 +1368,15 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 17 unmodified lines |
| 1062 | seg->maxprot = 7; // rwx | 1368 | seg->maxprot = 7; // rwx |
| 1063 | seg->initprot = 1; // r-- | 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 | mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep)); | 1380 | mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep)); |
| 1066 | mo->ep->entryoff = 4096; | 1381 | mo->ep->entryoff = 4096; |
| 1067 | | 1382 | |
| @@ -1071,7 +1386,6 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 3 unmodified lines |
| 1071 | str = (char*)dyldlc + dyldlc->name; | 1386 | str = (char*)dyldlc + dyldlc->name; |
| 1072 | strcpy(str, "/usr/lib/dyld"); | 1387 | strcpy(str, "/usr/lib/dyld"); |
| 1073 | | 1388 | |
| 1074 | mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo)); | | |
| 1075 | symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc)); | 1389 | symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc)); |
| 1076 | dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc)); | 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 | case SHT_PROGBITS: | 1423 | case SHT_PROGBITS: |
| 1110 | if (s == mo->stubs) | 1424 | if (s == mo->stubs) |
| 1111 | sk = sk_stubs; | 1425 | sk = sk_stubs; |
| | 1426 | #ifndef CONFIG_NEW_MACHO |
| 1112 | else if (s == mo->stub_helper) | 1427 | else if (s == mo->stub_helper) |
| 1113 | sk = sk_stub_helper; | 1428 | sk = sk_stub_helper; |
| 1114 | else if (s == s1->got) | | |
| 1115 | sk = sk_nl_ptr; | | |
| 1116 | else if (s == mo->la_symbol_ptr) | 1429 | else if (s == mo->la_symbol_ptr) |
| 1117 | sk = sk_la_ptr; | 1430 | sk = sk_la_ptr; |
| | 1431 | #endif |
| | 1432 | else if (s == s1->got) |
| | 1433 | sk = sk_nl_ptr; |
| 1118 | else if (s == stab_section) | 1434 | else if (s == stab_section) |
| 1119 | sk = sk_stab; | 1435 | sk = sk_stab; |
| 1120 | else if (s == dwarf_info_section) | 1436 | else if (s == dwarf_info_section) |
| @@ -1150,15 +1466,23 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 29 unmodified lines |
| 1150 | mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections); | 1466 | mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections); |
| 1151 | for (sk = sk_unknown; sk < sk_last; sk++) { | 1467 | for (sk = sk_unknown; sk < sk_last; sk++) { |
| 1152 | struct section_64 *sec = NULL; | 1468 | struct section_64 *sec = NULL; |
| 1153 | #define SEG_PAGE_SIZE 16384 | | |
| 1154 | if (sk == sk_linkedit) | | |
| 1155 | do_bind_rebase(s1, mo); | | |
| 1156 | if (seg) { | 1469 | if (seg) { |
| 1157 | seg->vmsize = (curaddr - seg->vmaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; | 1470 | seg->vmsize = (curaddr - seg->vmaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 1158 | seg->filesize = (fileofs - seg->fileoff + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; | 1471 | seg->filesize = (fileofs - seg->fileoff + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 1159 | curaddr = seg->vmaddr + seg->vmsize; | 1472 | curaddr = seg->vmaddr + seg->vmsize; |
| 1160 | fileofs = seg->fileoff + seg->filesize; | 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 | if (skinfo[sk].seg && mo->sk_to_sect[sk].s) { | 1486 | if (skinfo[sk].seg && mo->sk_to_sect[sk].s) { |
| 1163 | uint64_t al = 0; | 1487 | uint64_t al = 0; |
| 1164 | int si; | 1488 | int si; |
| @@ -1178,14 +1502,23 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 13 unmodified lines |
| 1178 | #endif | 1502 | #endif |
| 1179 | if (sk == sk_nl_ptr) | 1503 | if (sk == sk_nl_ptr) |
| 1180 | sec->reserved1 = mo->nr_plt; | 1504 | sec->reserved1 = mo->nr_plt; |
| | 1505 | #ifndef CONFIG_NEW_MACHO |
| 1181 | if (sk == sk_la_ptr) | 1506 | if (sk == sk_la_ptr) |
| 1182 | sec->reserved1 = mo->nr_plt + mo->n_got; | 1507 | sec->reserved1 = mo->nr_plt + mo->n_got; |
| | 1508 | #endif |
| 1183 | } | 1509 | } |
| 1184 | if (seg->vmaddr == -1) { | 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 | curaddr = (curaddr + 4095) & -4096; | 1517 | curaddr = (curaddr + 4095) & -4096; |
| 1186 | seg->vmaddr = curaddr; | 1518 | seg->vmaddr = curaddr; |
| 1187 | fileofs = (fileofs + 4095) & -4096; | 1519 | fileofs = (fileofs + 4095) & -4096; |
| 1188 | seg->fileoff = fileofs; | 1520 | seg->fileoff = fileofs; |
| | 1521 | #endif |
| 1189 | } | 1522 | } |
| 1190 | | 1523 | |
| 1191 | for (s = mo->sk_to_sect[sk].s; s; s = s->prev) { | 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 | dysymlc->indirectsymoff = mo->indirsyms->sh_offset; | 1599 | dysymlc->indirectsymoff = mo->indirsyms->sh_offset; |
| 1267 | dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t); | 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 | if (mo->rebase->data_offset) { | 1612 | if (mo->rebase->data_offset) { |
| 1270 | mo->dyldinfo->rebase_off = mo->rebase->sh_offset; | 1613 | mo->dyldinfo->rebase_off = mo->rebase->sh_offset; |
| 1271 | mo->dyldinfo->rebase_size = mo->rebase->data_offset; | 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 | mo->dyldinfo->export_off = mo->exports->sh_offset; | 1629 | mo->dyldinfo->export_off = mo->exports->sh_offset; |
| 1287 | mo->dyldinfo->export_size = mo->exports->data_offset; | 1630 | mo->dyldinfo->export_size = mo->exports->data_offset; |
| 1288 | } | 1631 | } |
| | 1632 | #endif |
| 1289 | } | 1633 | } |
| 1290 | | 1634 | |
| 1291 | static void macho_write(TCCState *s1, struct macho *mo, FILE *fp) | 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 | ST_FUNC int macho_output_file(TCCState *s1, const char *filename) | 1844 | ST_FUNC int macho_output_file(TCCState *s1, const char *filename) |
| 1337 | { | 1845 | { |
| 1338 | int fd, mode, file_type; | 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 | if (s1->nb_errors) | 1878 | if (s1->nb_errors) |
| 1371 | goto do_ret; | 1879 | goto do_ret; |
| 1372 | relocate_sections(s1); | 1880 | relocate_sections(s1); |
| | 1881 | #ifdef CONFIG_NEW_MACHO |
| | 1882 | bind_rebase_import(s1, &mo); |
| | 1883 | #endif |
| 1373 | convert_symbols(s1, &mo); | 1884 | convert_symbols(s1, &mo); |
| 1374 | macho_write(s1, &mo, fp); | 1885 | macho_write(s1, &mo, fp); |
| 1375 | } | 1886 | } |