| @@ -31,9 +31,28 @@ · 30 unmodified lines |
| 31 | to setup our own crt code. We're not using lazy linking, so even function | 31 | to setup our own crt code. We're not using lazy linking, so even function |
| 32 | calls are resolved at startup. */ | 32 | calls are resolved at startup. */ |
| 33 | | 33 | |
| | 34 | #if !defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64 |
| | 35 | #error Platform not supported |
| | 36 | #endif |
| | 37 | |
| 34 | #define DEBUG_MACHO 0 | 38 | #define DEBUG_MACHO 0 |
| 35 | #define dprintf if (DEBUG_MACHO) printf | 39 | #define dprintf if (DEBUG_MACHO) printf |
| 36 | | 40 | |
| | 41 | #define MH_EXECUTE (0x2) |
| | 42 | #define MH_DYLDLINK (0x4) |
| | 43 | #define MH_PIE (0x200000) |
| | 44 | |
| | 45 | #define CPU_SUBTYPE_LIB64 (0x80000000) |
| | 46 | #define CPU_SUBTYPE_X86_ALL (3) |
| | 47 | #define CPU_SUBTYPE_ARM64_ALL (0) |
| | 48 | |
| | 49 | #define CPU_ARCH_ABI64 (0x01000000) |
| | 50 | |
| | 51 | #define CPU_TYPE_X86 (7) |
| | 52 | #define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) |
| | 53 | #define CPU_TYPE_ARM (12) |
| | 54 | #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) |
| | 55 | |
| 37 | struct fat_header { | 56 | struct fat_header { |
| 38 | uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ | 57 | uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ |
| 39 | uint32_t nfat_arch; /* number of structs that follow */ | 58 | uint32_t nfat_arch; /* number of structs that follow */ |
| @@ -86,6 +105,7 @@ struct load_command { · 46 unmodified lines |
| 86 | #define LC_LOAD_DYLINKER 0xe | 105 | #define LC_LOAD_DYLINKER 0xe |
| 87 | #define LC_SEGMENT_64 0x19 | 106 | #define LC_SEGMENT_64 0x19 |
| 88 | #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) |
| 89 | #define LC_MAIN (0x28|LC_REQ_DYLD) | 109 | #define LC_MAIN (0x28|LC_REQ_DYLD) |
| 90 | | 110 | |
| 91 | typedef int vm_prot_t; | 111 | typedef int vm_prot_t; |
| @@ -122,6 +142,8 @@ struct section_64 { /* for 64-bit architectures */ · 30 unmodified lines |
| 122 | #define S_REGULAR 0x0 | 142 | #define S_REGULAR 0x0 |
| 123 | #define S_ZEROFILL 0x1 | 143 | #define S_ZEROFILL 0x1 |
| 124 | #define S_NON_LAZY_SYMBOL_POINTERS 0x6 | 144 | #define S_NON_LAZY_SYMBOL_POINTERS 0x6 |
| | 145 | #define S_LAZY_SYMBOL_POINTERS 0x7 |
| | 146 | #define S_SYMBOL_STUBS 0x8 |
| 125 | #define S_MOD_INIT_FUNC_POINTERS 0x9 | 147 | #define S_MOD_INIT_FUNC_POINTERS 0x9 |
| 126 | #define S_MOD_TERM_FUNC_POINTERS 0xa | 148 | #define S_MOD_TERM_FUNC_POINTERS 0xa |
| 127 | | 149 | |
| @@ -187,6 +209,38 @@ struct dysymtab_command { · 59 unmodified lines |
| 187 | uint32_t nlocrel; /* number of local relocation entries */ | 209 | uint32_t nlocrel; /* number of local relocation entries */ |
| 188 | }; | 210 | }; |
| 189 | | 211 | |
| | 212 | #define BIND_OPCODE_DONE 0x00 |
| | 213 | #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 |
| | 214 | #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 |
| | 215 | #define BIND_OPCODE_SET_TYPE_IMM 0x50 |
| | 216 | #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 |
| | 217 | #define BIND_OPCODE_DO_BIND 0x90 |
| | 218 | |
| | 219 | #define BIND_TYPE_POINTER 1 |
| | 220 | #define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 |
| | 221 | |
| | 222 | #define REBASE_OPCODE_DONE 0x00 |
| | 223 | #define REBASE_OPCODE_SET_TYPE_IMM 0x10 |
| | 224 | #define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20 |
| | 225 | #define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50 |
| | 226 | |
| | 227 | #define REBASE_TYPE_POINTER 1 |
| | 228 | |
| | 229 | struct dyld_info_command { |
| | 230 | uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ |
| | 231 | uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ |
| | 232 | uint32_t rebase_off; /* file offset to rebase info */ |
| | 233 | uint32_t rebase_size; /* size of rebase info */ |
| | 234 | uint32_t bind_off; /* file offset to binding info */ |
| | 235 | uint32_t bind_size; /* size of binding info */ |
| | 236 | uint32_t weak_bind_off; /* file offset to weak binding info */ |
| | 237 | uint32_t weak_bind_size; /* size of weak binding info */ |
| | 238 | uint32_t lazy_bind_off; /* file offset to lazy binding info */ |
| | 239 | uint32_t lazy_bind_size; /* size of lazy binding infs */ |
| | 240 | uint32_t export_off; /* file offset to lazy binding info */ |
| | 241 | uint32_t export_size; /* size of lazy binding infs */ |
| | 242 | }; |
| | 243 | |
| 190 | #define INDIRECT_SYMBOL_LOCAL 0x80000000 | 244 | #define INDIRECT_SYMBOL_LOCAL 0x80000000 |
| 191 | | 245 | |
| 192 | struct entry_point_command { | 246 | struct entry_point_command { |
| @@ -201,6 +255,7 @@ enum skind { · 8 unmodified lines |
| 201 | sk_discard, | 255 | sk_discard, |
| 202 | sk_text, | 256 | sk_text, |
| 203 | sk_stubs, | 257 | sk_stubs, |
| | 258 | sk_stub_helper, |
| 204 | sk_ro_data, | 259 | sk_ro_data, |
| 205 | sk_uw_info, | 260 | sk_uw_info, |
| 206 | sk_nl_ptr, // non-lazy pointers, aka GOT | 261 | sk_nl_ptr, // non-lazy pointers, aka GOT |
| @@ -208,6 +263,14 @@ enum skind { · 1 unmodified line |
| 208 | sk_init, | 263 | sk_init, |
| 209 | sk_fini, | 264 | sk_fini, |
| 210 | sk_rw_data, | 265 | sk_rw_data, |
| | 266 | sk_stab, |
| | 267 | sk_stab_str, |
| | 268 | sk_debug_info, |
| | 269 | sk_debug_abbrev, |
| | 270 | sk_debug_line, |
| | 271 | sk_debug_aranges, |
| | 272 | sk_debug_str, |
| | 273 | sk_debug_line_str, |
| 211 | sk_bss, | 274 | sk_bss, |
| 212 | sk_linkedit, | 275 | sk_linkedit, |
| 213 | sk_last | 276 | sk_last |
| @@ -241,9 +304,26 @@ struct macho { · 27 unmodified lines |
| 241 | } sk_to_sect[sk_last]; | 304 | } sk_to_sect[sk_last]; |
| 242 | int *elfsectomacho; | 305 | int *elfsectomacho; |
| 243 | int *e2msym; | 306 | int *e2msym; |
| 244 | Section *symtab, *strtab, *wdata, *indirsyms, *stubs; | 307 | Section *rebase, *binding, *lazy_binding, *exports; |
| 245 | int stubsym; | 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; |
| 246 | uint32_t ilocal, iextdef, iundef; | 313 | uint32_t ilocal, iextdef, iundef; |
| | 314 | int n_lazy_bind_rebase; |
| | 315 | struct lazy_bind_rebase { |
| | 316 | int section; |
| | 317 | int bind; |
| | 318 | int bind_offset; |
| | 319 | int la_symbol_offset; |
| | 320 | ElfW_Rel rel; |
| | 321 | } *lazy_bind_rebase; |
| | 322 | int n_bind; |
| | 323 | struct bind { |
| | 324 | int section; |
| | 325 | ElfW_Rel rel; |
| | 326 | } *bind; |
| 247 | }; | 327 | }; |
| 248 | | 328 | |
| 249 | #define SHT_LINKEDIT (SHT_LOOS + 42) | 329 | #define SHT_LINKEDIT (SHT_LOOS + 42) |
| @@ -306,20 +386,165 @@ static void * add_dylib(struct macho *mo, char *name) · 56 unmodified lines |
| 306 | return lc; | 386 | return lc; |
| 307 | } | 387 | } |
| 308 | | 388 | |
| | 389 | static void write_uleb128(Section *section, uint64_t value) |
| | 390 | { |
| | 391 | do { |
| | 392 | unsigned char byte = value & 0x7f; |
| | 393 | uint8_t *ptr = section_ptr_add(section, 1); |
| | 394 | |
| | 395 | value >>= 7; |
| | 396 | *ptr = byte | (value ? 0x80 : 0); |
| | 397 | } while (value != 0); |
| | 398 | } |
| | 399 | |
| | 400 | static void tcc_macho_add_destructor(TCCState *s1) |
| | 401 | { |
| | 402 | int init_sym, mh_execute_header, at_exit_sym; |
| | 403 | Section *s; |
| | 404 | ElfW_Rel *rel; |
| | 405 | uint8_t *ptr; |
| | 406 | |
| | 407 | s = find_section(s1, ".fini_array"); |
| | 408 | if (s->data_offset == 0) |
| | 409 | return; |
| | 410 | init_sym = put_elf_sym(s1->symtab, text_section->data_offset, 0, |
| | 411 | ELFW(ST_INFO)(STB_LOCAL, STT_FUNC), 0, |
| | 412 | text_section->sh_num, "___GLOBAL_init_65535"); |
| | 413 | mh_execute_header = put_elf_sym(s1->symtab, 0x100000000ll, 0, |
| | 414 | ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT), 0, |
| | 415 | SHN_ABS, "__mh_execute_header"); |
| | 416 | at_exit_sym = put_elf_sym(s1->symtab, 0, 0, |
| | 417 | ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, |
| | 418 | SHN_UNDEF, "___cxa_atexit"); |
| | 419 | #ifdef TCC_TARGET_X86_64 |
| | 420 | ptr = section_ptr_add(text_section, 4); |
| | 421 | ptr[0] = 0x55; // pushq %rbp |
| | 422 | ptr[1] = 0x48; // movq %rsp, %rbp |
| | 423 | ptr[2] = 0x89; |
| | 424 | ptr[3] = 0xe5; |
| | 425 | for_each_elem(s->reloc, 0, rel, ElfW_Rel) { |
| | 426 | int sym_index = ELFW(R_SYM)(rel->r_info); |
| | 427 | |
| | 428 | ptr = section_ptr_add(text_section, 26); |
| | 429 | ptr[0] = 0x48; // lea destructor(%rip),%rax |
| | 430 | ptr[1] = 0x8d; |
| | 431 | ptr[2] = 0x05; |
| | 432 | put_elf_reloca(s1->symtab, text_section, |
| | 433 | text_section->data_offset - 23, |
| | 434 | R_X86_64_PC32, sym_index, -4); |
| | 435 | ptr[7] = 0x48; // mov %rax,%rdi |
| | 436 | ptr[8] = 0x89; |
| | 437 | ptr[9] = 0xc7; |
| | 438 | ptr[10] = 0x31; // xorl %ecx, %ecx |
| | 439 | ptr[11] = 0xc9; |
| | 440 | ptr[12] = 0x89; // movl %ecx, %esi |
| | 441 | ptr[13] = 0xce; |
| | 442 | ptr[14] = 0x48; // lea mh_execute_header(%rip),%rdx |
| | 443 | ptr[15] = 0x8d; |
| | 444 | ptr[16] = 0x15; |
| | 445 | put_elf_reloca(s1->symtab, text_section, |
| | 446 | text_section->data_offset - 9, |
| | 447 | R_X86_64_PC32, mh_execute_header, -4); |
| | 448 | ptr[21] = 0xe8; // call __cxa_atexit |
| | 449 | put_elf_reloca(s1->symtab, text_section, |
| | 450 | text_section->data_offset - 4, |
| | 451 | R_X86_64_PLT32, at_exit_sym, -4); |
| | 452 | } |
| | 453 | ptr = section_ptr_add(text_section, 2); |
| | 454 | ptr[0] = 0x5d; // pop %rbp |
| | 455 | ptr[1] = 0xc3; // ret |
| | 456 | #elif defined TCC_TARGET_ARM64 |
| | 457 | ptr = section_ptr_add(text_section, 8); |
| | 458 | write32le(ptr, 0xa9bf7bfd); // stp x29, x30, [sp, #-16]! |
| | 459 | write32le(ptr + 4, 0x910003fd); // mov x29, sp |
| | 460 | for_each_elem(s->reloc, 0, rel, ElfW_Rel) { |
| | 461 | int sym_index = ELFW(R_SYM)(rel->r_info); |
| | 462 | |
| | 463 | ptr = section_ptr_add(text_section, 24); |
| | 464 | put_elf_reloc(s1->symtab, text_section, |
| | 465 | text_section->data_offset - 24, |
| | 466 | R_AARCH64_ADR_PREL_PG_HI21, sym_index); |
| | 467 | write32le(ptr, 0x90000000); // adrp x0, destructor@page |
| | 468 | put_elf_reloc(s1->symtab, text_section, |
| | 469 | text_section->data_offset - 20, |
| | 470 | R_AARCH64_LDST8_ABS_LO12_NC, sym_index); |
| | 471 | write32le(ptr + 4, 0x91000000); // add x0,x0,destructor@pageoff |
| | 472 | write32le(ptr + 8, 0xd2800001); // mov x1, #0 |
| | 473 | put_elf_reloc(s1->symtab, text_section, |
| | 474 | text_section->data_offset - 12, |
| | 475 | R_AARCH64_ADR_PREL_PG_HI21, mh_execute_header); |
| | 476 | write32le(ptr + 12, 0x90000002); // adrp x2, mh_execute_header@page |
| | 477 | put_elf_reloc(s1->symtab, text_section, |
| | 478 | text_section->data_offset - 8, |
| | 479 | R_AARCH64_LDST8_ABS_LO12_NC, mh_execute_header); |
| | 480 | write32le(ptr + 16, 0x91000042); // add x2,x2,mh_execute_header@pageoff |
| | 481 | put_elf_reloc(s1->symtab, text_section, |
| | 482 | text_section->data_offset - 4, |
| | 483 | R_AARCH64_CALL26, at_exit_sym); |
| | 484 | write32le(ptr + 20, 0x94000000); // bl __cxa_atexit |
| | 485 | } |
| | 486 | ptr = section_ptr_add(text_section, 8); |
| | 487 | write32le(ptr, 0xa8c17bfd); // ldp x29, x30, [sp], #16 |
| | 488 | write32le(ptr + 4, 0xd65f03c0); // ret |
| | 489 | #endif |
| | 490 | s->reloc->data_offset = s->data_offset = 0; |
| | 491 | s->sh_flags &= ~SHF_ALLOC; |
| | 492 | add_array (s1, ".init_array", init_sym); |
| | 493 | } |
| | 494 | |
| 309 | static void check_relocs(TCCState *s1, struct macho *mo) | 495 | static void check_relocs(TCCState *s1, struct macho *mo) |
| 310 | { | 496 | { |
| | 497 | uint8_t *jmp; |
| 311 | Section *s; | 498 | Section *s; |
| 312 | ElfW_Rel *rel; | 499 | ElfW_Rel *rel; |
| 313 | ElfW(Sym) *sym; | 500 | ElfW(Sym) *sym; |
| 314 | int i, type, gotplt_entry, sym_index, for_code; | 501 | int i, type, gotplt_entry, sym_index, for_code; |
| | 502 | int sh_num, debug, bind_offset, la_symbol_offset; |
| | 503 | uint32_t *pi, *goti; |
| 315 | struct sym_attr *attr; | 504 | struct sym_attr *attr; |
| 316 | | 505 | |
| 317 | s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); | | |
| 318 | mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 506 | mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| | 507 | |
| | 508 | #ifdef TCC_TARGET_X86_64 |
| | 509 | jmp = section_ptr_add(mo->stub_helper, 16); |
| | 510 | jmp[0] = 0x4c; /* leaq _dyld_private(%rip), %r11 */ |
| | 511 | jmp[1] = 0x8d; |
| | 512 | jmp[2] = 0x1d; |
| | 513 | put_elf_reloca(s1->symtab, mo->stub_helper, 3, |
| | 514 | R_X86_64_PC32, mo->dyld_private, -4); |
| | 515 | jmp[7] = 0x41; /* pushq %r11 */ |
| | 516 | jmp[8] = 0x53; |
| | 517 | jmp[9] = 0xff; /* jmpq *dyld_stub_binder@GOT(%rip) */ |
| | 518 | jmp[10] = 0x25; |
| | 519 | put_elf_reloca(s1->symtab, mo->stub_helper, 11, |
| | 520 | R_X86_64_GOTPCREL, mo->dyld_stub_binder, -4); |
| | 521 | jmp[15] = 0x90; /* nop */ |
| | 522 | #elif defined TCC_TARGET_ARM64 |
| | 523 | jmp = section_ptr_add(mo->stub_helper, 24); |
| | 524 | put_elf_reloc(s1->symtab, mo->stub_helper, 0, |
| | 525 | R_AARCH64_ADR_PREL_PG_HI21, mo->dyld_private); |
| | 526 | write32le(jmp, 0x90000011); // adrp x17, _dyld_private@page |
| | 527 | put_elf_reloc(s1->symtab, mo->stub_helper, 4, |
| | 528 | R_AARCH64_LDST64_ABS_LO12_NC, mo->dyld_private); |
| | 529 | write32le(jmp + 4, 0x91000231); // add x17,x17,_dyld_private@pageoff |
| | 530 | write32le(jmp + 8, 0xa9bf47f0); // stp x16/x17, [sp, #-16]! |
| | 531 | put_elf_reloc(s1->symtab, mo->stub_helper, 12, |
| | 532 | R_AARCH64_ADR_GOT_PAGE, mo->dyld_stub_binder); |
| | 533 | write32le(jmp + 12, 0x90000010); // adrp x16, dyld_stub_binder@page |
| | 534 | put_elf_reloc(s1->symtab, mo->stub_helper, 16, |
| | 535 | R_AARCH64_LD64_GOT_LO12_NC, mo->dyld_stub_binder); |
| | 536 | write32le(jmp + 16, 0xf9400210); // ldr x16,[x16,dyld_stub_binder@pageoff] |
| | 537 | write32le(jmp + 20, 0xd61f0200); // br x16 |
| | 538 | #endif |
| | 539 | |
| | 540 | goti = NULL; |
| | 541 | mo->nr_plt = mo->n_got = 0; |
| 319 | for (i = 1; i < s1->nb_sections; i++) { | 542 | for (i = 1; i < s1->nb_sections; i++) { |
| 320 | s = s1->sections[i]; | 543 | s = s1->sections[i]; |
| 321 | if (s->sh_type != SHT_RELX) | 544 | if (s->sh_type != SHT_RELX) |
| 322 | continue; | 545 | continue; |
| | 546 | sh_num = s1->sections[s->sh_info]->sh_num; |
| | 547 | debug = sh_num >= s1->dwlo && sh_num < s1->dwhi; |
| 323 | for_each_elem(s, 0, rel, ElfW_Rel) { | 548 | for_each_elem(s, 0, rel, ElfW_Rel) { |
| 324 | type = ELFW(R_TYPE)(rel->r_info); | 549 | type = ELFW(R_TYPE)(rel->r_info); |
| 325 | gotplt_entry = gotplt_entry_type(type); | 550 | gotplt_entry = gotplt_entry_type(type); |
| @@ -329,44 +554,150 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 3 unmodified lines |
| 329 | address due to codegen (i.e. a reloc requiring a got slot). */ | 554 | address due to codegen (i.e. a reloc requiring a got slot). */ |
| 330 | sym_index = ELFW(R_SYM)(rel->r_info); | 555 | sym_index = ELFW(R_SYM)(rel->r_info); |
| 331 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | 556 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 332 | if (sym->st_shndx == SHN_UNDEF | 557 | if (!debug && |
| 333 | || gotplt_entry == ALWAYS_GOTPLT_ENTRY) { | 558 | (sym->st_shndx == SHN_UNDEF |
| | 559 | || gotplt_entry == ALWAYS_GOTPLT_ENTRY)) { |
| 334 | attr = get_sym_attr(s1, sym_index, 1); | 560 | attr = get_sym_attr(s1, sym_index, 1); |
| 335 | if (!attr->dyn_index) { | 561 | if (!attr->dyn_index) { |
| 336 | uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); | | |
| 337 | attr->got_offset = s1->got->data_offset; | 562 | attr->got_offset = s1->got->data_offset; |
| 338 | attr->plt_offset = -1; | 563 | attr->plt_offset = -1; |
| 339 | attr->dyn_index = 1; /* used as flag */ | 564 | attr->dyn_index = 1; /* used as flag */ |
| 340 | section_ptr_add(s1->got, PTR_SIZE); | 565 | section_ptr_add(s1->got, PTR_SIZE); |
| | 566 | put_elf_reloc(s1->symtab, s1->got, attr->got_offset, |
| | 567 | R_DATA_PTR, sym_index); |
| | 568 | goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti)); |
| 341 | if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { | 569 | if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { |
| 342 | if (sym->st_shndx == SHN_UNDEF) | 570 | if (sym->st_shndx == SHN_UNDEF) |
| 343 | tcc_error("undefined local symbol???"); | 571 | tcc_error("undefined local symbo: '%s'", |
| 344 | *pi = INDIRECT_SYMBOL_LOCAL; | 572 | (char *) symtab_section->link->data + sym->st_name); |
| 345 | /* The pointer slot we generated must point to the | 573 | goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL; |
| 346 | symbol, whose address is only known after layout, | 574 | } else { |
| 347 | so register a simple relocation for that. */ | 575 | goti[mo->n_got++] = mo->e2msym[sym_index]; |
| 348 | put_elf_reloc(s1->symtab, s1->got, attr->got_offset, | 576 | if (sym->st_shndx == SHN_UNDEF |
| 349 | R_DATA_PTR, sym_index); | 577 | #ifdef TCC_TARGET_X86_64 |
| 350 | } else | 578 | && type == R_X86_64_GOTPCREL |
| 351 | *pi = mo->e2msym[sym_index]; | 579 | #elif defined TCC_TARGET_ARM64 |
| | 580 | && type == R_AARCH64_ADR_GOT_PAGE |
| | 581 | #endif |
| | 582 | ) { |
| | 583 | mo->bind = |
| | 584 | tcc_realloc(mo->bind, |
| | 585 | (mo->n_bind + 1) * |
| | 586 | sizeof(struct bind)); |
| | 587 | mo->bind[mo->n_bind].section = s1->got->reloc->sh_info; |
| | 588 | mo->bind[mo->n_bind].rel = *rel; |
| | 589 | mo->bind[mo->n_bind].rel.r_offset = attr->got_offset; |
| | 590 | mo->n_bind++; |
| | 591 | s1->got->reloc->data_offset -= sizeof (ElfW_Rel); |
| | 592 | } |
| | 593 | } |
| 352 | } | 594 | } |
| 353 | if (for_code) { | 595 | if (for_code && sym->st_shndx == SHN_UNDEF) { |
| 354 | if (attr->plt_offset == -1) { | 596 | if (attr->plt_offset == -1) { |
| 355 | uint8_t *jmp; | 597 | pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); |
| | 598 | *pi = mo->e2msym[sym_index]; |
| | 599 | mo->nr_plt++; |
| 356 | attr->plt_offset = mo->stubs->data_offset; | 600 | attr->plt_offset = mo->stubs->data_offset; |
| | 601 | #ifdef TCC_TARGET_X86_64 |
| | 602 | if (type != R_X86_64_PLT32) |
| | 603 | continue; |
| | 604 | /* __stubs */ |
| 357 | jmp = section_ptr_add(mo->stubs, 6); | 605 | jmp = section_ptr_add(mo->stubs, 6); |
| 358 | jmp[0] = 0xff; /* jmpq *ofs(%rip) */ | 606 | jmp[0] = 0xff; /* jmpq *__la_symbol_ptr(%rip) */ |
| 359 | jmp[1] = 0x25; | 607 | jmp[1] = 0x25; |
| 360 | put_elf_reloc(s1->symtab, mo->stubs, | 608 | put_elf_reloca(s1->symtab, mo->stubs, |
| 361 | attr->plt_offset + 2, | 609 | mo->stubs->data_offset - 4, |
| 362 | R_X86_64_GOTPCREL, sym_index); | 610 | R_X86_64_PC32, mo->lasym, |
| | 611 | mo->la_symbol_ptr->data_offset - 4); |
| | 612 | |
| | 613 | /* __stub_helper */ |
| | 614 | bind_offset = mo->stub_helper->data_offset + 1; |
| | 615 | jmp = section_ptr_add(mo->stub_helper, 10); |
| | 616 | jmp[0] = 0x68; /* pushq $bind_offset */ |
| | 617 | jmp[5] = 0xe9; /* jmpq __stub_helper */ |
| | 618 | write32le(jmp + 6, -mo->stub_helper->data_offset); |
| | 619 | |
| | 620 | /* __la_symbol_ptr */ |
| | 621 | la_symbol_offset = mo->la_symbol_ptr->data_offset; |
| | 622 | put_elf_reloca(s1->symtab, mo->la_symbol_ptr, |
| | 623 | mo->la_symbol_ptr->data_offset, |
| | 624 | R_DATA_PTR, mo->helpsym, |
| | 625 | mo->stub_helper->data_offset - 10); |
| | 626 | jmp = section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); |
| | 627 | #elif defined TCC_TARGET_ARM64 |
| | 628 | if (type != R_AARCH64_CALL26) |
| | 629 | continue; |
| | 630 | /* __stubs */ |
| | 631 | jmp = section_ptr_add(mo->stubs, 12); |
| | 632 | put_elf_reloca(s1->symtab, mo->stubs, |
| | 633 | mo->stubs->data_offset - 12, |
| | 634 | R_AARCH64_ADR_PREL_PG_HI21, mo->lasym, |
| | 635 | mo->la_symbol_ptr->data_offset); |
| | 636 | write32le(jmp, // adrp x16, __la_symbol_ptr@page |
| | 637 | 0x90000010); |
| | 638 | put_elf_reloca(s1->symtab, mo->stubs, |
| | 639 | mo->stubs->data_offset - 8, |
| | 640 | R_AARCH64_LDST64_ABS_LO12_NC, mo->lasym, |
| | 641 | mo->la_symbol_ptr->data_offset); |
| | 642 | write32le(jmp + 4, // ldr x16,[x16, __la_symbol_ptr@pageoff] |
| | 643 | 0xf9400210); |
| | 644 | write32le(jmp + 8, // br x16 |
| | 645 | 0xd61f0200); |
| | 646 | |
| | 647 | /* __stub_helper */ |
| | 648 | bind_offset = mo->stub_helper->data_offset + 8; |
| | 649 | jmp = section_ptr_add(mo->stub_helper, 12); |
| | 650 | write32le(jmp + 0, // ldr w16, l0 |
| | 651 | 0x18000050); |
| | 652 | write32le(jmp + 4, // b stubHelperHeader |
| | 653 | 0x14000000 + |
| | 654 | ((-(mo->stub_helper->data_offset - 8) / 4) & |
| | 655 | 0x3ffffff)); |
| | 656 | write32le(jmp + 8, 0); // l0: .long bind_offset |
| | 657 | |
| | 658 | /* __la_symbol_ptr */ |
| | 659 | la_symbol_offset = mo->la_symbol_ptr->data_offset; |
| | 660 | put_elf_reloca(s1->symtab, mo->la_symbol_ptr, |
| | 661 | mo->la_symbol_ptr->data_offset, |
| | 662 | R_DATA_PTR, mo->helpsym, |
| | 663 | mo->stub_helper->data_offset - 12); |
| | 664 | jmp = section_ptr_add(mo->la_symbol_ptr, PTR_SIZE); |
| | 665 | #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 = |
| | 671 | 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 = |
| | 677 | attr->plt_offset; |
| | 678 | mo->n_lazy_bind_rebase++; |
| 363 | } | 679 | } |
| 364 | rel->r_info = ELFW(R_INFO)(mo->stubsym, type); | 680 | rel->r_info = ELFW(R_INFO)(mo->stubsym, type); |
| 365 | rel->r_addend += attr->plt_offset; | 681 | rel->r_addend += attr->plt_offset; |
| 366 | } | 682 | } |
| 367 | } | 683 | } |
| | 684 | 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++; |
| | 693 | } |
| 368 | } | 694 | } |
| 369 | } | 695 | } |
| | 696 | pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi)); |
| | 697 | memcpy(pi, goti, mo->n_got * sizeof(*pi)); |
| | 698 | pi = section_ptr_add(mo->indirsyms, mo->nr_plt * sizeof(*pi)); |
| | 699 | memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi)); |
| | 700 | tcc_free(goti); |
| 370 | } | 701 | } |
| 371 | | 702 | |
| 372 | static int check_symbols(TCCState *s1, struct macho *mo) | 703 | static int check_symbols(TCCState *s1, struct macho *mo) |
| @@ -444,9 +775,12 @@ static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn) · 71 unmodified lines |
| 444 | n.n_type = N_ABS, n.n_sect = 0; | 775 | n.n_type = N_ABS, n.n_sect = 0; |
| 445 | else if (sym->st_shndx >= SHN_LORESERVE) | 776 | else if (sym->st_shndx >= SHN_LORESERVE) |
| 446 | tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name); | 777 | tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name); |
| 447 | else if (!mo->elfsectomacho[sym->st_shndx]) | 778 | else if (!mo->elfsectomacho[sym->st_shndx]) { |
| 448 | tcc_error("ELF section %d not mapped into Mach-O for symbol %s", | 779 | int sh_num = s1->sections[sym->st_shndx]->sh_num; |
| 449 | sym->st_shndx, name); | 780 | if (sh_num < s1->dwlo || sh_num >= s1->dwhi) |
| | 781 | tcc_error("ELF section %d(%s) not mapped into Mach-O for symbol %s", |
| | 782 | sym->st_shndx, s1->sections[sym->st_shndx]->name, name); |
| | 783 | } |
| 450 | else | 784 | else |
| 451 | n.n_sect = mo->elfsectomacho[sym->st_shndx]; | 785 | n.n_sect = mo->elfsectomacho[sym->st_shndx]; |
| 452 | if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL) | 786 | if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL) |
| @@ -465,9 +799,9 @@ static void convert_symbols(TCCState *s1, struct macho *mo) · 12 unmodified lines |
| 465 | convert_symbol(s1, mo, pn); | 799 | convert_symbol(s1, mo, pn); |
| 466 | } | 800 | } |
| 467 | | 801 | |
| 468 | static int machosymcmp(const void *_a, const void *_b) | 802 | static int machosymcmp(const void *_a, const void *_b, void *arg) |
| 469 | { | 803 | { |
| 470 | TCCState *s1 = tcc_state; | 804 | TCCState *s1 = arg; |
| 471 | int ea = ((struct nlist_64 *)_a)->n_value; | 805 | int ea = ((struct nlist_64 *)_a)->n_value; |
| 472 | int eb = ((struct nlist_64 *)_b)->n_value; | 806 | int eb = ((struct nlist_64 *)_b)->n_value; |
| 473 | ElfSym *sa = (ElfSym *)symtab_section->data + ea; | 807 | ElfSym *sa = (ElfSym *)symtab_section->data + ea; |
| @@ -492,6 +826,37 @@ static int machosymcmp(const void *_a, const void *_b) · 18 unmodified lines |
| 492 | return ea - eb; | 826 | return ea - eb; |
| 493 | } | 827 | } |
| 494 | | 828 | |
| | 829 | /* cannot use qsort because code has to be reentrant */ |
| | 830 | static void tcc_qsort (void *base, size_t nel, size_t width, |
| | 831 | int (*comp)(const void *, const void *, void *), void *arg) |
| | 832 | { |
| | 833 | size_t wnel, gap, wgap, i, j, k; |
| | 834 | char *a, *b, tmp; |
| | 835 | |
| | 836 | wnel = width * nel; |
| | 837 | for (gap = 0; ++gap < nel;) |
| | 838 | gap *= 3; |
| | 839 | while ( gap /= 3 ) { |
| | 840 | wgap = width * gap; |
| | 841 | for (i = wgap; i < wnel; i += width) { |
| | 842 | for (j = i - wgap; ;j -= wgap) { |
| | 843 | a = j + (char *)base; |
| | 844 | b = a + wgap; |
| | 845 | if ( (*comp)(a, b, arg) <= 0 ) |
| | 846 | break; |
| | 847 | k = width; |
| | 848 | do { |
| | 849 | tmp = *a; |
| | 850 | *a++ = *b; |
| | 851 | *b++ = tmp; |
| | 852 | } while ( --k ); |
| | 853 | if (j < wgap) |
| | 854 | break; |
| | 855 | } |
| | 856 | } |
| | 857 | } |
| | 858 | } |
| | 859 | |
| 495 | static void create_symtab(TCCState *s1, struct macho *mo) | 860 | static void create_symtab(TCCState *s1, struct macho *mo) |
| 496 | { | 861 | { |
| 497 | int sym_index, sym_end; | 862 | int sym_index, sym_end; |
| @@ -500,9 +865,30 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 2 unmodified lines |
| 500 | /* Stub creation belongs to check_relocs, but we need to create | 865 | /* Stub creation belongs to check_relocs, but we need to create |
| 501 | the symbol now, so its included in the sorting. */ | 866 | the symbol now, so its included in the sorting. */ |
| 502 | mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); | 867 | 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); |
| | 870 | mo->la_symbol_ptr = new_section(s1, "__la_symbol_ptr", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 503 | mo->stubsym = put_elf_sym(s1->symtab, 0, 0, | 871 | mo->stubsym = put_elf_sym(s1->symtab, 0, 0, |
| 504 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, | 872 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| 505 | mo->stubs->sh_num, ".__stubs"); | 873 | mo->stubs->sh_num, ".__stubs"); |
| | 874 | mo->helpsym = put_elf_sym(s1->symtab, 0, 0, |
| | 875 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| | 876 | mo->stub_helper->sh_num, ".__stub_helper"); |
| | 877 | mo->lasym = put_elf_sym(s1->symtab, 0, 0, |
| | 878 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| | 879 | mo->la_symbol_ptr->sh_num, ".__la_symbol_ptr"); |
| | 880 | section_ptr_add(data_section, -data_section->data_offset & (PTR_SIZE - 1)); |
| | 881 | mo->dyld_private = put_elf_sym(s1->symtab, data_section->data_offset, PTR_SIZE, |
| | 882 | ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT), 0, |
| | 883 | data_section->sh_num, ".__dyld_private"); |
| | 884 | section_ptr_add(data_section, PTR_SIZE); |
| | 885 | mo->dyld_stub_binder = put_elf_sym(s1->symtab, 0, 0, |
| | 886 | ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0, |
| | 887 | SHN_UNDEF, "dyld_stub_binder"); |
| | 888 | mo->rebase = new_section(s1, "REBASE", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| | 889 | mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| | 890 | mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| | 891 | mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 506 | | 892 | |
| 507 | mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 893 | mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 508 | mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); | 894 | mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| @@ -515,9 +901,7 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 6 unmodified lines |
| 515 | pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name); | 901 | pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name); |
| 516 | pn[sym_index - 1].n_value = sym_index; | 902 | pn[sym_index - 1].n_value = sym_index; |
| 517 | } | 903 | } |
| 518 | tcc_enter_state(s1); /* qsort needs global state */ | 904 | tcc_qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp, s1); |
| 519 | qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp); | | |
| 520 | tcc_exit_state(s1); | | |
| 521 | mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym)); | 905 | mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym)); |
| 522 | mo->e2msym[0] = -1; | 906 | mo->e2msym[0] = -1; |
| 523 | for (sym_index = 1; sym_index < sym_end; ++sym_index) { | 907 | for (sym_index = 1; sym_index < sym_end; ++sym_index) { |
| @@ -530,22 +914,121 @@ const struct { · 6 unmodified lines |
| 530 | uint32_t flags; | 914 | uint32_t flags; |
| 531 | const char *name; | 915 | const char *name; |
| 532 | } skinfo[sk_last] = { | 916 | } skinfo[sk_last] = { |
| 533 | /*[sk_unknown] =*/ { 0 }, | 917 | /*[sk_unknown] =*/ { 0 }, |
| 534 | /*[sk_discard] =*/ { 0 }, | 918 | /*[sk_discard] =*/ { 0 }, |
| 535 | /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | 919 | /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS |
| 536 | | S_ATTR_SOME_INSTRUCTIONS, "__text" }, | 920 | | S_ATTR_SOME_INSTRUCTIONS, "__text" }, |
| 537 | /*[sk_stubs] =*/ { 0 }, | 921 | /*[sk_stubs] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_SYMBOL_STUBS |
| 538 | /*[sk_ro_data] =*/ { 1, S_REGULAR, "__rodata" }, | 922 | | S_ATTR_SOME_INSTRUCTIONS , "__stubs" }, |
| 539 | /*[sk_uw_info] =*/ { 0 }, | 923 | /*[sk_stub_helper] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS |
| 540 | /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" }, | 924 | | S_ATTR_SOME_INSTRUCTIONS , "__stub_helper" }, |
| 541 | /*[sk_la_ptr] =*/ { 0 }, | 925 | /*[sk_ro_data] =*/ { 1, S_REGULAR, "__rodata" }, |
| 542 | /*[sk_init] =*/ { 2, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" }, | 926 | /*[sk_uw_info] =*/ { 0 }, |
| 543 | /*[sk_fini] =*/ { 2, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" }, | 927 | /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" }, |
| 544 | /*[sk_rw_data] =*/ { 2, S_REGULAR, "__data" }, | 928 | /*[sk_la_ptr] =*/ { 2, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" }, |
| 545 | /*[sk_bss] =*/ { 2, S_ZEROFILL, "__bss" }, | 929 | /*[sk_init] =*/ { 2, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" }, |
| 546 | /*[sk_linkedit] =*/ { 3, S_REGULAR, NULL }, | 930 | /*[sk_fini] =*/ { 2, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" }, |
| | 931 | /*[sk_rw_data] =*/ { 2, S_REGULAR, "__data" }, |
| | 932 | /*[sk_stab] =*/ { 2, S_REGULAR, "__stab" }, |
| | 933 | /*[sk_stab_str] =*/ { 2, S_REGULAR, "__stab_str" }, |
| | 934 | /*[sk_debug_info] =*/ { 2, S_REGULAR, "__debug_info" }, |
| | 935 | /*[sk_debug_abbrev] =*/ { 2, S_REGULAR, "__debug_abbrev" }, |
| | 936 | /*[sk_debug_line] =*/ { 2, S_REGULAR, "__debug_line" }, |
| | 937 | /*[sk_debug_aranges] =*/ { 2, S_REGULAR, "__debug_aranges" }, |
| | 938 | /*[sk_debug_str] =*/ { 2, S_REGULAR, "__debug_str" }, |
| | 939 | /*[sk_debug_line_str] =*/ { 2, S_REGULAR, "__debug_line_str" }, |
| | 940 | /*[sk_bss] =*/ { 2, S_ZEROFILL, "__bss" }, |
| | 941 | /*[sk_linkedit] =*/ { 3, S_REGULAR, NULL }, |
| 547 | }; | 942 | }; |
| 548 | | 943 | |
| | 944 | static void set_segment_and_offset(struct macho *mo, addr_t addr, |
| | 945 | uint8_t *ptr, int opcode, |
| | 946 | Section *sec, addr_t offset) |
| | 947 | { |
| | 948 | int i; |
| | 949 | struct segment_command_64 *seg = NULL; |
| | 950 | |
| | 951 | for (i = 1; i < mo->nseg - 1; i++) { |
| | 952 | seg = get_segment(mo, i); |
| | 953 | if (addr >= seg->vmaddr && addr < (seg->vmaddr + seg->vmsize)) |
| | 954 | break; |
| | 955 | } |
| | 956 | *ptr = opcode | i; |
| | 957 | write_uleb128(sec, offset - seg->vmaddr); |
| | 958 | } |
| | 959 | |
| | 960 | static void do_bind_rebase(TCCState *s1, struct macho *mo) |
| | 961 | { |
| | 962 | int i; |
| | 963 | uint8_t *ptr; |
| | 964 | ElfW(Sym) *sym; |
| | 965 | char *name; |
| | 966 | |
| | 967 | for (i = 0; i < mo->n_lazy_bind_rebase; i++) { |
| | 968 | int sym_index = ELFW(R_SYM)(mo->lazy_bind_rebase[i].rel.r_info); |
| | 969 | Section *s = s1->sections[mo->lazy_bind_rebase[i].section]; |
| | 970 | |
| | 971 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| | 972 | name = (char *) symtab_section->link->data + sym->st_name; |
| | 973 | if (mo->lazy_bind_rebase[i].bind) { |
| | 974 | write32le(mo->stub_helper->data + |
| | 975 | mo->lazy_bind_rebase[i].bind_offset, |
| | 976 | mo->lazy_binding->data_offset); |
| | 977 | ptr = section_ptr_add(mo->lazy_binding, 1); |
| | 978 | set_segment_and_offset(mo, mo->la_symbol_ptr->sh_addr, ptr, |
| | 979 | BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| | 980 | mo->lazy_binding, |
| | 981 | mo->la_symbol_ptr->sh_addr + |
| | 982 | mo->lazy_bind_rebase[i].la_symbol_offset); |
| | 983 | ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name)); |
| | 984 | *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | |
| | 985 | (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); |
| | 986 | *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; |
| | 987 | strcpy(ptr, name); |
| | 988 | ptr += strlen(name) + 1; |
| | 989 | *ptr++ = BIND_OPCODE_DO_BIND; |
| | 990 | *ptr = BIND_OPCODE_DONE; |
| | 991 | } |
| | 992 | else { |
| | 993 | ptr = section_ptr_add(mo->rebase, 2); |
| | 994 | *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER; |
| | 995 | set_segment_and_offset(mo, s->sh_addr, ptr, |
| | 996 | REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| | 997 | mo->rebase, |
| | 998 | mo->lazy_bind_rebase[i].rel.r_offset + |
| | 999 | s->sh_addr); |
| | 1000 | ptr = section_ptr_add(mo->rebase, 1); |
| | 1001 | *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1; |
| | 1002 | } |
| | 1003 | } |
| | 1004 | for (i = 0; i < mo->n_bind; i++) { |
| | 1005 | int sym_index = ELFW(R_SYM)(mo->bind[i].rel.r_info); |
| | 1006 | Section *s = s1->sections[mo->bind[i].section]; |
| | 1007 | |
| | 1008 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| | 1009 | name = (char *) symtab_section->link->data + sym->st_name; |
| | 1010 | ptr = section_ptr_add(mo->binding, 5 + strlen(name)); |
| | 1011 | *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | |
| | 1012 | (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf); |
| | 1013 | *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0; |
| | 1014 | strcpy(ptr, name); |
| | 1015 | ptr += strlen(name) + 1; |
| | 1016 | *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER; |
| | 1017 | set_segment_and_offset(mo, s->sh_addr, ptr, |
| | 1018 | BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, |
| | 1019 | mo->binding, |
| | 1020 | mo->bind[i].rel.r_offset + s->sh_addr); |
| | 1021 | ptr = section_ptr_add(mo->binding, 1); |
| | 1022 | *ptr++ = BIND_OPCODE_DO_BIND; |
| | 1023 | } |
| | 1024 | if (mo->rebase->data_offset) { |
| | 1025 | ptr = section_ptr_add(mo->rebase, 1); |
| | 1026 | *ptr = REBASE_OPCODE_DONE; |
| | 1027 | } |
| | 1028 | tcc_free(mo->lazy_bind_rebase); |
| | 1029 | tcc_free(mo->bind); |
| | 1030 | } |
| | 1031 | |
| 549 | static void collect_sections(TCCState *s1, struct macho *mo) | 1032 | static void collect_sections(TCCState *s1, struct macho *mo) |
| 550 | { | 1033 | { |
| 551 | int i, sk, numsec; | 1034 | int i, sk, numsec; |
| @@ -584,6 +1067,7 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 32 unmodified lines |
| 584 | str = (char*)dyldlc + dyldlc->name; | 1067 | str = (char*)dyldlc + dyldlc->name; |
| 585 | strcpy(str, "/usr/lib/dyld"); | 1068 | strcpy(str, "/usr/lib/dyld"); |
| 586 | | 1069 | |
| | 1070 | mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo)); |
| 587 | symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc)); | 1071 | symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc)); |
| 588 | dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc)); | 1072 | dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc)); |
| 589 | | 1073 | |
| @@ -610,12 +1094,37 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 20 unmodified lines |
| 610 | case SHT_FINI_ARRAY: sk = sk_fini; break; | 1094 | case SHT_FINI_ARRAY: sk = sk_fini; break; |
| 611 | case SHT_NOBITS: sk = sk_bss; break; | 1095 | case SHT_NOBITS: sk = sk_bss; break; |
| 612 | case SHT_SYMTAB: sk = sk_discard; break; | 1096 | case SHT_SYMTAB: sk = sk_discard; break; |
| 613 | case SHT_STRTAB: sk = s == stabstr_section ? sk_ro_data : sk_discard; break; | 1097 | case SHT_STRTAB: |
| | 1098 | if (s == stabstr_section) |
| | 1099 | sk = sk_stab_str; |
| | 1100 | else |
| | 1101 | sk = sk_discard; |
| | 1102 | break; |
| 614 | case SHT_RELX: sk = sk_discard; break; | 1103 | case SHT_RELX: sk = sk_discard; break; |
| 615 | case SHT_LINKEDIT: sk = sk_linkedit; break; | 1104 | case SHT_LINKEDIT: sk = sk_linkedit; break; |
| 616 | case SHT_PROGBITS: | 1105 | case SHT_PROGBITS: |
| 617 | if (s == s1->got) | 1106 | if (s == mo->stubs) |
| | 1107 | sk = sk_stubs; |
| | 1108 | else if (s == mo->stub_helper) |
| | 1109 | sk = sk_stub_helper; |
| | 1110 | else if (s == s1->got) |
| 618 | sk = sk_nl_ptr; | 1111 | sk = sk_nl_ptr; |
| | 1112 | else if (s == mo->la_symbol_ptr) |
| | 1113 | sk = sk_la_ptr; |
| | 1114 | else if (s == stab_section) |
| | 1115 | sk = sk_stab; |
| | 1116 | else if (s == dwarf_info_section) |
| | 1117 | sk = sk_debug_info; |
| | 1118 | else if (s == dwarf_abbrev_section) |
| | 1119 | sk = sk_debug_abbrev; |
| | 1120 | else if (s == dwarf_line_section) |
| | 1121 | sk = sk_debug_line; |
| | 1122 | else if (s == dwarf_aranges_section) |
| | 1123 | sk = sk_debug_aranges; |
| | 1124 | else if (s == dwarf_str_section) |
| | 1125 | sk = sk_debug_str; |
| | 1126 | else if (s == dwarf_line_str_section) |
| | 1127 | sk = sk_debug_line_str; |
| 619 | else if (flags & SHF_EXECINSTR) | 1128 | else if (flags & SHF_EXECINSTR) |
| 620 | sk = sk_text; | 1129 | sk = sk_text; |
| 621 | else if (flags & SHF_WRITE) | 1130 | else if (flags & SHF_WRITE) |
| @@ -637,9 +1146,14 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 15 unmodified lines |
| 637 | mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections); | 1146 | mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections); |
| 638 | for (sk = sk_unknown; sk < sk_last; sk++) { | 1147 | for (sk = sk_unknown; sk < sk_last; sk++) { |
| 639 | struct section_64 *sec = NULL; | 1148 | struct section_64 *sec = NULL; |
| | 1149 | #define SEG_PAGE_SIZE 16384 |
| | 1150 | if (sk == sk_linkedit) |
| | 1151 | do_bind_rebase(s1, mo); |
| 640 | if (seg) { | 1152 | if (seg) { |
| 641 | seg->vmsize = curaddr - seg->vmaddr; | 1153 | seg->vmsize = (curaddr - seg->vmaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 642 | seg->filesize = fileofs - seg->fileoff; | 1154 | seg->filesize = (fileofs - seg->fileoff + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| | 1155 | curaddr = seg->vmaddr + seg->vmsize; |
| | 1156 | fileofs = seg->fileoff + seg->filesize; |
| 643 | } | 1157 | } |
| 644 | if (skinfo[sk].seg && mo->sk_to_sect[sk].s) { | 1158 | if (skinfo[sk].seg && mo->sk_to_sect[sk].s) { |
| 645 | uint64_t al = 0; | 1159 | uint64_t al = 0; |
| @@ -652,6 +1166,16 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 6 unmodified lines |
| 652 | mo->sk_to_sect[sk].machosect = si; | 1166 | mo->sk_to_sect[sk].machosect = si; |
| 653 | sec = get_section(seg, si); | 1167 | sec = get_section(seg, si); |
| 654 | sec->flags = skinfo[sk].flags; | 1168 | sec->flags = skinfo[sk].flags; |
| | 1169 | if (sk == sk_stubs) |
| | 1170 | #ifdef TCC_TARGET_X86_64 |
| | 1171 | sec->reserved2 = 6; |
| | 1172 | #elif defined TCC_TARGET_ARM64 |
| | 1173 | sec->reserved2 = 12; |
| | 1174 | #endif |
| | 1175 | if (sk == sk_nl_ptr) |
| | 1176 | sec->reserved1 = mo->nr_plt; |
| | 1177 | if (sk == sk_la_ptr) |
| | 1178 | sec->reserved1 = mo->nr_plt + mo->n_got; |
| 655 | } | 1179 | } |
| 656 | if (seg->vmaddr == -1) { | 1180 | if (seg->vmaddr == -1) { |
| 657 | curaddr = (curaddr + 4095) & -4096; | 1181 | curaddr = (curaddr + 4095) & -4096; |
| @@ -737,6 +1261,23 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 79 unmodified lines |
| 737 | dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym; | 1261 | dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym; |
| 738 | dysymlc->indirectsymoff = mo->indirsyms->sh_offset; | 1262 | dysymlc->indirectsymoff = mo->indirsyms->sh_offset; |
| 739 | dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t); | 1263 | dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t); |
| | 1264 | |
| | 1265 | if (mo->rebase->data_offset) { |
| | 1266 | mo->dyldinfo->rebase_off = mo->rebase->sh_offset; |
| | 1267 | mo->dyldinfo->rebase_size = mo->rebase->data_offset; |
| | 1268 | } |
| | 1269 | if (mo->binding->data_offset) { |
| | 1270 | mo->dyldinfo->bind_off = mo->binding->sh_offset; |
| | 1271 | mo->dyldinfo->bind_size = mo->binding->data_offset; |
| | 1272 | } |
| | 1273 | if (mo->lazy_binding->data_offset) { |
| | 1274 | mo->dyldinfo->lazy_bind_off = mo->lazy_binding->sh_offset; |
| | 1275 | mo->dyldinfo->lazy_bind_size = mo->lazy_binding->data_offset; |
| | 1276 | } |
| | 1277 | if (mo->exports->data_offset) { |
| | 1278 | mo->dyldinfo->export_off = mo->exports->sh_offset; |
| | 1279 | mo->dyldinfo->export_size = mo->exports->data_offset; |
| | 1280 | } |
| 740 | } | 1281 | } |
| 741 | | 1282 | |
| 742 | static void macho_write(TCCState *s1, struct macho *mo, FILE *fp) | 1283 | static void macho_write(TCCState *s1, struct macho *mo, FILE *fp) |
| @@ -745,10 +1286,15 @@ static void macho_write(TCCState *s1, struct macho *mo, FILE *fp) · 2 unmodified lines |
| 745 | uint64_t fileofs = 0; | 1286 | uint64_t fileofs = 0; |
| 746 | Section *s; | 1287 | Section *s; |
| 747 | mo->mh.mh.magic = MH_MAGIC_64; | 1288 | mo->mh.mh.magic = MH_MAGIC_64; |
| 748 | mo->mh.mh.cputype = 0x1000007; // x86_64 | 1289 | #ifdef TCC_TARGET_X86_64 |
| 749 | mo->mh.mh.cpusubtype = 0x80000003;// all | CPU_SUBTYPE_LIB64 | 1290 | mo->mh.mh.cputype = CPU_TYPE_X86_64; |
| 750 | mo->mh.mh.filetype = 2; // MH_EXECUTE | 1291 | mo->mh.mh.cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_ALL; |
| 751 | mo->mh.mh.flags = 4; // DYLDLINK | 1292 | #elif defined TCC_TARGET_ARM64 |
| | 1293 | mo->mh.mh.cputype = CPU_TYPE_ARM64; |
| | 1294 | mo->mh.mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL; |
| | 1295 | #endif |
| | 1296 | mo->mh.mh.filetype = MH_EXECUTE; |
| | 1297 | mo->mh.mh.flags = MH_DYLDLINK | MH_PIE; |
| 752 | mo->mh.mh.ncmds = mo->nlc; | 1298 | mo->mh.mh.ncmds = mo->nlc; |
| 753 | mo->mh.mh.sizeofcmds = 0; | 1299 | mo->mh.mh.sizeofcmds = 0; |
| 754 | for (i = 0; i < mo->nlc; i++) | 1300 | for (i = 0; i < mo->nlc; i++) |
| @@ -803,6 +1349,7 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) · 48 unmodified lines |
| 803 | printf("<- %s\n", filename); | 1349 | printf("<- %s\n", filename); |
| 804 | | 1350 | |
| 805 | tcc_add_runtime(s1); | 1351 | tcc_add_runtime(s1); |
| | 1352 | tcc_macho_add_destructor(s1); |
| 806 | resolve_common_syms(s1); | 1353 | resolve_common_syms(s1); |
| 807 | create_symtab(s1, &mo); | 1354 | create_symtab(s1, &mo); |
| 808 | check_relocs(s1, &mo); | 1355 | check_relocs(s1, &mo); |
| @@ -959,8 +1506,13 @@ ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev) · 150 unmodified lines |
| 959 | fh.nfat_arch * sizeof(*fa)); | 1506 | fh.nfat_arch * sizeof(*fa)); |
| 960 | swap = fh.magic == FAT_CIGAM; | 1507 | swap = fh.magic == FAT_CIGAM; |
| 961 | for (i = 0; i < SWAP(fh.nfat_arch); i++) | 1508 | for (i = 0; i < SWAP(fh.nfat_arch); i++) |
| 962 | if (SWAP(fa[i].cputype) == 0x01000007 /* CPU_TYPE_X86_64 */ | 1509 | #ifdef TCC_TARGET_X86_64 |
| 963 | && SWAP(fa[i].cpusubtype) == 3) /* CPU_SUBTYPE_X86_ALL */ | 1510 | if (SWAP(fa[i].cputype) == CPU_TYPE_X86_64 |
| | 1511 | && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_X86_ALL) |
| | 1512 | #elif defined TCC_TARGET_ARM64 |
| | 1513 | if (SWAP(fa[i].cputype) == CPU_TYPE_ARM64 |
| | 1514 | && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_ARM64_ALL) |
| | 1515 | #endif |
| 964 | break; | 1516 | break; |
| 965 | if (i == SWAP(fh.nfat_arch)) { | 1517 | if (i == SWAP(fh.nfat_arch)) { |
| 966 | tcc_free(fa); | 1518 | tcc_free(fa); |