| ... | ... | @@ -403,6 +403,13 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 403 | 403 | } |
| 404 | 404 | try self.addPtrBindingOrRebase(rel, target, context); |
| 405 | 405 | }, |
| 406 | .ARM64_RELOC_TLVP_LOAD_PAGE21, |
| 407 | .ARM64_RELOC_TLVP_LOAD_PAGEOFF12, |
| 408 | => { |
| 409 | if (target == .global) { |
| 410 | try addTlvPtrEntry(target, context); |
| 411 | } |
| 412 | }, |
| 406 | 413 | else => {}, |
| 407 | 414 | } |
| 408 | 415 | }, |
| ... | ... | @@ -452,6 +459,11 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 452 | 459 | @intCast(i64, target_sect_base_addr); |
| 453 | 460 | } |
| 454 | 461 | }, |
| 462 | .X86_64_RELOC_TLV => { |
| 463 | if (target == .global) { |
| 464 | try addTlvPtrEntry(target, context); |
| 465 | } |
| 466 | }, |
| 455 | 467 | else => {}, |
| 456 | 468 | } |
| 457 | 469 | }, |
| ... | ... | @@ -531,6 +543,47 @@ fn addPtrBindingOrRebase( |
| 531 | 543 | } |
| 532 | 544 | } |
| 533 | 545 | |
| 546 | fn addTlvPtrEntry(target: Relocation.Target, context: RelocContext) !void { |
| 547 | if (context.macho_file.tlv_ptr_entries_map.contains(target)) return; |
| 548 | |
| 549 | const value_ptr = blk: { |
| 550 | if (context.macho_file.tlv_ptr_entries_map_free_list.popOrNull()) |i| { |
| 551 | log.debug("reusing __thread_ptrs entry index {d} for {}", .{ i, target }); |
| 552 | context.macho_file.tlv_ptr_entries_map.keys()[i] = target; |
| 553 | const value_ptr = context.macho_file.tlv_ptr_entries_map.getPtr(target).?; |
| 554 | break :blk value_ptr; |
| 555 | } else { |
| 556 | const res = try context.macho_file.tlv_ptr_entries_map.getOrPut( |
| 557 | context.macho_file.base.allocator, |
| 558 | target, |
| 559 | ); |
| 560 | log.debug("creating new __thread_ptrs entry at index {d} for {}", .{ |
| 561 | context.macho_file.tlv_ptr_entries_map.getIndex(target).?, |
| 562 | target, |
| 563 | }); |
| 564 | break :blk res.value_ptr; |
| 565 | } |
| 566 | }; |
| 567 | const atom = try context.macho_file.createTlvPtrAtom(target); |
| 568 | value_ptr.* = atom; |
| 569 | |
| 570 | const match = (try context.macho_file.getMatchingSection(.{ |
| 571 | .segname = MachO.makeStaticString("__DATA"), |
| 572 | .sectname = MachO.makeStaticString("__thread_ptrs"), |
| 573 | .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS, |
| 574 | })).?; |
| 575 | if (!context.object.start_atoms.contains(match)) { |
| 576 | try context.object.start_atoms.putNoClobber(context.allocator, match, atom); |
| 577 | } |
| 578 | if (context.object.end_atoms.getPtr(match)) |last| { |
| 579 | last.*.next = atom; |
| 580 | atom.prev = last.*; |
| 581 | last.* = atom; |
| 582 | } else { |
| 583 | try context.object.end_atoms.putNoClobber(context.allocator, match, atom); |
| 584 | } |
| 585 | } |
| 586 | |
| 534 | 587 | fn addGotEntry(target: Relocation.Target, context: RelocContext) !void { |
| 535 | 588 | if (context.macho_file.got_entries_map.contains(target)) return; |
| 536 | 589 | |
| ... | ... | @@ -667,6 +720,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 667 | 720 | const sym = macho_file.locals.items[self.local_sym_index]; |
| 668 | 721 | break :blk sym.n_value + rel.offset; |
| 669 | 722 | }; |
| 723 | var is_via_thread_ptrs: bool = false; |
| 670 | 724 | const target_addr = blk: { |
| 671 | 725 | const is_via_got = got: { |
| 672 | 726 | switch (arch) { |
| ... | ... | @@ -742,8 +796,13 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 742 | 796 | .undef => { |
| 743 | 797 | break :blk if (macho_file.stubs_map.get(n_strx)) |atom| |
| 744 | 798 | macho_file.locals.items[atom.local_sym_index].n_value |
| 745 | | else |
| 746 | | 0; |
| 799 | else inner: { |
| 800 | if (macho_file.tlv_ptr_entries_map.get(rel.target)) |atom| { |
| 801 | is_via_thread_ptrs = true; |
| 802 | break :inner macho_file.locals.items[atom.local_sym_index].n_value; |
| 803 | } |
| 804 | break :inner 0; |
| 805 | }; |
| 747 | 806 | }, |
| 748 | 807 | } |
| 749 | 808 | }, |
| ... | ... | @@ -854,10 +913,12 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 854 | 913 | }, |
| 855 | 914 | .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { |
| 856 | 915 | const code = self.code.items[rel.offset..][0..4]; |
| 916 | const actual_target_addr = @intCast(i64, target_addr) + rel.addend; |
| 917 | |
| 857 | 918 | const RegInfo = struct { |
| 858 | 919 | rd: u5, |
| 859 | 920 | rn: u5, |
| 860 | | size: u1, |
| 921 | size: u2, |
| 861 | 922 | }; |
| 862 | 923 | const reg_info: RegInfo = blk: { |
| 863 | 924 | if (isArithmeticOp(code)) { |
| ... | ... | @@ -878,13 +939,25 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 878 | 939 | break :blk .{ |
| 879 | 940 | .rd = inst.rt, |
| 880 | 941 | .rn = inst.rn, |
| 881 | | .size = @truncate(u1, inst.size), |
| 942 | .size = inst.size, |
| 882 | 943 | }; |
| 883 | 944 | } |
| 884 | 945 | }; |
| 885 | | const actual_target_addr = @intCast(i64, target_addr) + rel.addend; |
| 886 | 946 | const narrowed = @truncate(u12, @intCast(u64, actual_target_addr)); |
| 887 | | var inst = aarch64.Instruction{ |
| 947 | var inst = if (is_via_thread_ptrs) blk: { |
| 948 | const offset = try math.divExact(u12, narrowed, 8); |
| 949 | break :blk aarch64.Instruction{ |
| 950 | .load_store_register = .{ |
| 951 | .rt = reg_info.rd, |
| 952 | .rn = reg_info.rn, |
| 953 | .offset = offset, |
| 954 | .opc = 0b01, |
| 955 | .op1 = 0b01, |
| 956 | .v = 0, |
| 957 | .size = reg_info.size, |
| 958 | }, |
| 959 | }; |
| 960 | } else aarch64.Instruction{ |
| 888 | 961 | .add_subtract_immediate = .{ |
| 889 | 962 | .rd = reg_info.rd, |
| 890 | 963 | .rn = reg_info.rn, |
| ... | ... | @@ -892,7 +965,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 892 | 965 | .sh = 0, |
| 893 | 966 | .s = 0, |
| 894 | 967 | .op = 0, |
| 895 | | .sf = reg_info.size, |
| 968 | .sf = @truncate(u1, reg_info.size), |
| 896 | 969 | }, |
| 897 | 970 | }; |
| 898 | 971 | mem.writeIntLittle(u32, code, inst.toU32()); |
| ... | ... | @@ -942,8 +1015,10 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 942 | 1015 | mem.writeIntLittle(u32, self.code.items[rel.offset..][0..4], @bitCast(u32, displacement)); |
| 943 | 1016 | }, |
| 944 | 1017 | .X86_64_RELOC_TLV => { |
| 945 | | // We need to rewrite the opcode from movq to leaq. |
| 946 | | self.code.items[rel.offset - 2] = 0x8d; |
| 1018 | if (!is_via_thread_ptrs) { |
| 1019 | // We need to rewrite the opcode from movq to leaq. |
| 1020 | self.code.items[rel.offset - 2] = 0x8d; |
| 1021 | } |
| 947 | 1022 | const displacement = try math.cast( |
| 948 | 1023 | i32, |
| 949 | 1024 | @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4 + rel.addend, |