| @@ -31,9 +31,28 @@ · 30 unmodified lines |
| 31 | 31 | to setup our own crt code. We're not using lazy linking, so even function |
| 32 | 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 | 38 | #define DEBUG_MACHO 0 |
| 35 | 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 | 56 | struct fat_header { |
| 38 | 57 | uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ |
| 39 | 58 | uint32_t nfat_arch; /* number of structs that follow */ |
| @@ -86,6 +105,7 @@ struct load_command { · 46 unmodified lines |
| 86 | 105 | #define LC_LOAD_DYLINKER 0xe |
| 87 | 106 | #define LC_SEGMENT_64 0x19 |
| 88 | 107 | #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) |
| 108 | +#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) |
| 89 | 109 | #define LC_MAIN (0x28|LC_REQ_DYLD) |
| 90 | 110 | |
| 91 | 111 | typedef int vm_prot_t; |
| @@ -122,6 +142,8 @@ struct section_64 { /* for 64-bit architectures */ · 30 unmodified lines |
| 122 | 142 | #define S_REGULAR 0x0 |
| 123 | 143 | #define S_ZEROFILL 0x1 |
| 124 | 144 | #define S_NON_LAZY_SYMBOL_POINTERS 0x6 |
| 145 | +#define S_LAZY_SYMBOL_POINTERS 0x7 |
| 146 | +#define S_SYMBOL_STUBS 0x8 |
| 125 | 147 | #define S_MOD_INIT_FUNC_POINTERS 0x9 |
| 126 | 148 | #define S_MOD_TERM_FUNC_POINTERS 0xa |
| 127 | 149 | |
| @@ -187,6 +209,38 @@ struct dysymtab_command { · 59 unmodified lines |
| 187 | 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 | 244 | #define INDIRECT_SYMBOL_LOCAL 0x80000000 |
| 191 | 245 | |
| 192 | 246 | struct entry_point_command { |
| @@ -201,6 +255,7 @@ enum skind { · 8 unmodified lines |
| 201 | 255 | sk_discard, |
| 202 | 256 | sk_text, |
| 203 | 257 | sk_stubs, |
| 258 | + sk_stub_helper, |
| 204 | 259 | sk_ro_data, |
| 205 | 260 | sk_uw_info, |
| 206 | 261 | sk_nl_ptr, // non-lazy pointers, aka GOT |
| @@ -208,6 +263,14 @@ enum skind { · 1 unmodified line |
| 208 | 263 | sk_init, |
| 209 | 264 | sk_fini, |
| 210 | 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 | 274 | sk_bss, |
| 212 | 275 | sk_linkedit, |
| 213 | 276 | sk_last |
| @@ -241,9 +304,26 @@ struct macho { · 27 unmodified lines |
| 241 | 304 | } sk_to_sect[sk_last]; |
| 242 | 305 | int *elfsectomacho; |
| 243 | 306 | int *e2msym; |
| 244 | | − Section *symtab, *strtab, *wdata, *indirsyms, *stubs; |
| 245 | | − int stubsym; |
| 307 | + Section *rebase, *binding, *lazy_binding, *exports; |
| 308 | + Section *symtab, *strtab, *wdata, *indirsyms; |
| 309 | + Section *stubs, *stub_helper, *la_symbol_ptr; |
| 310 | + int nr_plt, n_got; |
| 311 | + struct dyld_info_command *dyldinfo; |
| 312 | + int stubsym, helpsym, lasym, dyld_private, dyld_stub_binder; |
| 246 | 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 | 329 | #define SHT_LINKEDIT (SHT_LOOS + 42) |
| @@ -306,20 +386,165 @@ static void * add_dylib(struct macho *mo, char *name) · 56 unmodified lines |
| 306 | 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 | 495 | static void check_relocs(TCCState *s1, struct macho *mo) |
| 310 | 496 | { |
| 497 | + uint8_t *jmp; |
| 311 | 498 | Section *s; |
| 312 | 499 | ElfW_Rel *rel; |
| 313 | 500 | ElfW(Sym) *sym; |
| 314 | 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 | 504 | struct sym_attr *attr; |
| 316 | 505 | |
| 317 | | − s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 318 | 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 | 542 | for (i = 1; i < s1->nb_sections; i++) { |
| 320 | 543 | s = s1->sections[i]; |
| 321 | 544 | if (s->sh_type != SHT_RELX) |
| 322 | 545 | continue; |
| 546 | + sh_num = s1->sections[s->sh_info]->sh_num; |
| 547 | + debug = sh_num >= s1->dwlo && sh_num < s1->dwhi; |
| 323 | 548 | for_each_elem(s, 0, rel, ElfW_Rel) { |
| 324 | 549 | type = ELFW(R_TYPE)(rel->r_info); |
| 325 | 550 | gotplt_entry = gotplt_entry_type(type); |
| @@ -329,44 +554,150 @@ static void check_relocs(TCCState *s1, struct macho *mo) · 3 unmodified lines |
| 329 | 554 | address due to codegen (i.e. a reloc requiring a got slot). */ |
| 330 | 555 | sym_index = ELFW(R_SYM)(rel->r_info); |
| 331 | 556 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 332 | | − if (sym->st_shndx == SHN_UNDEF |
| 333 | | − || gotplt_entry == ALWAYS_GOTPLT_ENTRY) { |
| 557 | + if (!debug && |
| 558 | + (sym->st_shndx == SHN_UNDEF |
| 559 | + || gotplt_entry == ALWAYS_GOTPLT_ENTRY)) { |
| 334 | 560 | attr = get_sym_attr(s1, sym_index, 1); |
| 335 | 561 | if (!attr->dyn_index) { |
| 336 | | − uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); |
| 337 | 562 | attr->got_offset = s1->got->data_offset; |
| 338 | 563 | attr->plt_offset = -1; |
| 339 | 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 | 569 | if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { |
| 342 | 570 | if (sym->st_shndx == SHN_UNDEF) |
| 343 | | − tcc_error("undefined local symbol???"); |
| 344 | | − *pi = INDIRECT_SYMBOL_LOCAL; |
| 345 | | − /* The pointer slot we generated must point to the |
| 346 | | − symbol, whose address is only known after layout, |
| 347 | | − so register a simple relocation for that. */ |
| 348 | | − put_elf_reloc(s1->symtab, s1->got, attr->got_offset, |
| 349 | | − R_DATA_PTR, sym_index); |
| 350 | | − } else |
| 351 | | − *pi = mo->e2msym[sym_index]; |
| 571 | + tcc_error("undefined local symbo: '%s'", |
| 572 | + (char *) symtab_section->link->data + sym->st_name); |
| 573 | + goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL; |
| 574 | + } else { |
| 575 | + goti[mo->n_got++] = mo->e2msym[sym_index]; |
| 576 | + if (sym->st_shndx == SHN_UNDEF |
| 577 | +#ifdef TCC_TARGET_X86_64 |
| 578 | + && type == R_X86_64_GOTPCREL |
| 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 | 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 | 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 | 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 | 607 | jmp[1] = 0x25; |
| 360 | | − put_elf_reloc(s1->symtab, mo->stubs, |
| 361 | | − attr->plt_offset + 2, |
| 362 | | − R_X86_64_GOTPCREL, sym_index); |
| 608 | + put_elf_reloca(s1->symtab, mo->stubs, |
| 609 | + mo->stubs->data_offset - 4, |
| 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 | 680 | rel->r_info = ELFW(R_INFO)(mo->stubsym, type); |
| 365 | 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 | 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 | 775 | n.n_type = N_ABS, n.n_sect = 0; |
| 445 | 776 | else if (sym->st_shndx >= SHN_LORESERVE) |
| 446 | 777 | tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name); |
| 447 | | − else if (!mo->elfsectomacho[sym->st_shndx]) |
| 448 | | − tcc_error("ELF section %d not mapped into Mach-O for symbol %s", |
| 449 | | − sym->st_shndx, name); |
| 778 | + else if (!mo->elfsectomacho[sym->st_shndx]) { |
| 779 | + int sh_num = s1->sections[sym->st_shndx]->sh_num; |
| 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 | 784 | else |
| 451 | 785 | n.n_sect = mo->elfsectomacho[sym->st_shndx]; |
| 452 | 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 | 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 | 805 | int ea = ((struct nlist_64 *)_a)->n_value; |
| 472 | 806 | int eb = ((struct nlist_64 *)_b)->n_value; |
| 473 | 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 | 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 | 860 | static void create_symtab(TCCState *s1, struct macho *mo) |
| 496 | 861 | { |
| 497 | 862 | int sym_index, sym_end; |
| @@ -500,9 +865,30 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 2 unmodified lines |
| 500 | 865 | /* Stub creation belongs to check_relocs, but we need to create |
| 501 | 866 | the symbol now, so its included in the sorting. */ |
| 502 | 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 | 871 | mo->stubsym = put_elf_sym(s1->symtab, 0, 0, |
| 504 | 872 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| 505 | 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 | 893 | mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 508 | 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 | 901 | pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name); |
| 516 | 902 | pn[sym_index - 1].n_value = sym_index; |
| 517 | 903 | } |
| 518 | | − tcc_enter_state(s1); /* qsort needs global state */ |
| 519 | | − qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp); |
| 520 | | − tcc_exit_state(s1); |
| 904 | + tcc_qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp, s1); |
| 521 | 905 | mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym)); |
| 522 | 906 | mo->e2msym[0] = -1; |
| 523 | 907 | for (sym_index = 1; sym_index < sym_end; ++sym_index) { |
| @@ -530,22 +914,121 @@ const struct { · 6 unmodified lines |
| 530 | 914 | uint32_t flags; |
| 531 | 915 | const char *name; |
| 532 | 916 | } skinfo[sk_last] = { |
| 533 | | − /*[sk_unknown] =*/ { 0 }, |
| 534 | | − /*[sk_discard] =*/ { 0 }, |
| 535 | | − /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS |
| 536 | | − | S_ATTR_SOME_INSTRUCTIONS, "__text" }, |
| 537 | | − /*[sk_stubs] =*/ { 0 }, |
| 538 | | − /*[sk_ro_data] =*/ { 1, S_REGULAR, "__rodata" }, |
| 539 | | − /*[sk_uw_info] =*/ { 0 }, |
| 540 | | − /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" }, |
| 541 | | − /*[sk_la_ptr] =*/ { 0 }, |
| 542 | | − /*[sk_init] =*/ { 2, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" }, |
| 543 | | − /*[sk_fini] =*/ { 2, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" }, |
| 544 | | − /*[sk_rw_data] =*/ { 2, S_REGULAR, "__data" }, |
| 545 | | − /*[sk_bss] =*/ { 2, S_ZEROFILL, "__bss" }, |
| 546 | | − /*[sk_linkedit] =*/ { 3, S_REGULAR, NULL }, |
| 917 | + /*[sk_unknown] =*/ { 0 }, |
| 918 | + /*[sk_discard] =*/ { 0 }, |
| 919 | + /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS |
| 920 | + | S_ATTR_SOME_INSTRUCTIONS, "__text" }, |
| 921 | + /*[sk_stubs] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_SYMBOL_STUBS |
| 922 | + | S_ATTR_SOME_INSTRUCTIONS , "__stubs" }, |
| 923 | + /*[sk_stub_helper] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS |
| 924 | + | S_ATTR_SOME_INSTRUCTIONS , "__stub_helper" }, |
| 925 | + /*[sk_ro_data] =*/ { 1, S_REGULAR, "__rodata" }, |
| 926 | + /*[sk_uw_info] =*/ { 0 }, |
| 927 | + /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" }, |
| 928 | + /*[sk_la_ptr] =*/ { 2, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" }, |
| 929 | + /*[sk_init] =*/ { 2, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" }, |
| 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 | 1032 | static void collect_sections(TCCState *s1, struct macho *mo) |
| 550 | 1033 | { |
| 551 | 1034 | int i, sk, numsec; |
| @@ -584,6 +1067,7 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 32 unmodified lines |
| 584 | 1067 | str = (char*)dyldlc + dyldlc->name; |
| 585 | 1068 | strcpy(str, "/usr/lib/dyld"); |
| 586 | 1069 | |
| 1070 | + mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo)); |
| 587 | 1071 | symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc)); |
| 588 | 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 | 1094 | case SHT_FINI_ARRAY: sk = sk_fini; break; |
| 611 | 1095 | case SHT_NOBITS: sk = sk_bss; break; |
| 612 | 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 | 1103 | case SHT_RELX: sk = sk_discard; break; |
| 615 | 1104 | case SHT_LINKEDIT: sk = sk_linkedit; break; |
| 616 | 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 | 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 | 1128 | else if (flags & SHF_EXECINSTR) |
| 620 | 1129 | sk = sk_text; |
| 621 | 1130 | else if (flags & SHF_WRITE) |
| @@ -637,9 +1146,14 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 15 unmodified lines |
| 637 | 1146 | mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections); |
| 638 | 1147 | for (sk = sk_unknown; sk < sk_last; sk++) { |
| 639 | 1148 | struct section_64 *sec = NULL; |
| 1149 | +#define SEG_PAGE_SIZE 16384 |
| 1150 | + if (sk == sk_linkedit) |
| 1151 | + do_bind_rebase(s1, mo); |
| 640 | 1152 | if (seg) { |
| 641 | | − seg->vmsize = curaddr - seg->vmaddr; |
| 642 | | − seg->filesize = fileofs - seg->fileoff; |
| 1153 | + seg->vmsize = (curaddr - seg->vmaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE; |
| 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 | 1158 | if (skinfo[sk].seg && mo->sk_to_sect[sk].s) { |
| 645 | 1159 | uint64_t al = 0; |
| @@ -652,6 +1166,16 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 6 unmodified lines |
| 652 | 1166 | mo->sk_to_sect[sk].machosect = si; |
| 653 | 1167 | sec = get_section(seg, si); |
| 654 | 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 | 1180 | if (seg->vmaddr == -1) { |
| 657 | 1181 | curaddr = (curaddr + 4095) & -4096; |
| @@ -737,6 +1261,23 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 79 unmodified lines |
| 737 | 1261 | dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym; |
| 738 | 1262 | dysymlc->indirectsymoff = mo->indirsyms->sh_offset; |
| 739 | 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 | 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 | 1286 | uint64_t fileofs = 0; |
| 746 | 1287 | Section *s; |
| 747 | 1288 | mo->mh.mh.magic = MH_MAGIC_64; |
| 748 | | − mo->mh.mh.cputype = 0x1000007; // x86_64 |
| 749 | | − mo->mh.mh.cpusubtype = 0x80000003;// all | CPU_SUBTYPE_LIB64 |
| 750 | | − mo->mh.mh.filetype = 2; // MH_EXECUTE |
| 751 | | − mo->mh.mh.flags = 4; // DYLDLINK |
| 1289 | +#ifdef TCC_TARGET_X86_64 |
| 1290 | + mo->mh.mh.cputype = CPU_TYPE_X86_64; |
| 1291 | + mo->mh.mh.cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_ALL; |
| 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 | 1298 | mo->mh.mh.ncmds = mo->nlc; |
| 753 | 1299 | mo->mh.mh.sizeofcmds = 0; |
| 754 | 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 | 1349 | printf("<- %s\n", filename); |
| 804 | 1350 | |
| 805 | 1351 | tcc_add_runtime(s1); |
| 1352 | + tcc_macho_add_destructor(s1); |
| 806 | 1353 | resolve_common_syms(s1); |
| 807 | 1354 | create_symtab(s1, &mo); |
| 808 | 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 | 1506 | fh.nfat_arch * sizeof(*fa)); |
| 960 | 1507 | swap = fh.magic == FAT_CIGAM; |
| 961 | 1508 | for (i = 0; i < SWAP(fh.nfat_arch); i++) |
| 962 | | − if (SWAP(fa[i].cputype) == 0x01000007 /* CPU_TYPE_X86_64 */ |
| 963 | | − && SWAP(fa[i].cpusubtype) == 3) /* CPU_SUBTYPE_X86_ALL */ |
| 1509 | +#ifdef TCC_TARGET_X86_64 |
| 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 | 1516 | break; |
| 965 | 1517 | if (i == SWAP(fh.nfat_arch)) { |
| 966 | 1518 | tcc_free(fa); |