| ... | @@ -403,6 +403,13 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -403,6 +403,13 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 403 | } | 403 | } |
| 404 | try self.addPtrBindingOrRebase(rel, target, context); | 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 | else => {}, | 413 | else => {}, |
| 407 | } | 414 | } |
| 408 | }, | 415 | }, |
| ... | @@ -452,6 +459,11 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -452,6 +459,11 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 452 | @intCast(i64, target_sect_base_addr); | 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 | else => {}, | 467 | else => {}, |
| 456 | } | 468 | } |
| 457 | }, | 469 | }, |
| ... | @@ -531,6 +543,47 @@ fn addPtrBindingOrRebase( | ... | @@ -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 | fn addGotEntry(target: Relocation.Target, context: RelocContext) !void { | 587 | fn addGotEntry(target: Relocation.Target, context: RelocContext) !void { |
| 535 | if (context.macho_file.got_entries_map.contains(target)) return; | 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,6 +720,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 667 | const sym = macho_file.locals.items[self.local_sym_index]; | 720 | const sym = macho_file.locals.items[self.local_sym_index]; |
| 668 | break :blk sym.n_value + rel.offset; | 721 | break :blk sym.n_value + rel.offset; |
| 669 | }; | 722 | }; |
| | 723 | var is_via_thread_ptrs: bool = false; |
| 670 | const target_addr = blk: { | 724 | const target_addr = blk: { |
| 671 | const is_via_got = got: { | 725 | const is_via_got = got: { |
| 672 | switch (arch) { | 726 | switch (arch) { |
| ... | @@ -742,8 +796,13 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -742,8 +796,13 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 742 | .undef => { | 796 | .undef => { |
| 743 | break :blk if (macho_file.stubs_map.get(n_strx)) |atom| | 797 | break :blk if (macho_file.stubs_map.get(n_strx)) |atom| |
| 744 | macho_file.locals.items[atom.local_sym_index].n_value | 798 | macho_file.locals.items[atom.local_sym_index].n_value |
| 745 | else | 799 | else inner: { |
| 746 | 0; | 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,10 +913,12 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 854 | }, | 913 | }, |
| 855 | .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { | 914 | .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { |
| 856 | const code = self.code.items[rel.offset..][0..4]; | 915 | const code = self.code.items[rel.offset..][0..4]; |
| | 916 | const actual_target_addr = @intCast(i64, target_addr) + rel.addend; |
| | 917 | |
| 857 | const RegInfo = struct { | 918 | const RegInfo = struct { |
| 858 | rd: u5, | 919 | rd: u5, |
| 859 | rn: u5, | 920 | rn: u5, |
| 860 | size: u1, | 921 | size: u2, |
| 861 | }; | 922 | }; |
| 862 | const reg_info: RegInfo = blk: { | 923 | const reg_info: RegInfo = blk: { |
| 863 | if (isArithmeticOp(code)) { | 924 | if (isArithmeticOp(code)) { |
| ... | @@ -878,13 +939,25 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -878,13 +939,25 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 878 | break :blk .{ | 939 | break :blk .{ |
| 879 | .rd = inst.rt, | 940 | .rd = inst.rt, |
| 880 | .rn = inst.rn, | 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 | const narrowed = @truncate(u12, @intCast(u64, actual_target_addr)); | 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 | .add_subtract_immediate = .{ | 961 | .add_subtract_immediate = .{ |
| 889 | .rd = reg_info.rd, | 962 | .rd = reg_info.rd, |
| 890 | .rn = reg_info.rn, | 963 | .rn = reg_info.rn, |
| ... | @@ -892,7 +965,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -892,7 +965,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 892 | .sh = 0, | 965 | .sh = 0, |
| 893 | .s = 0, | 966 | .s = 0, |
| 894 | .op = 0, | 967 | .op = 0, |
| 895 | .sf = reg_info.size, | 968 | .sf = @truncate(u1, reg_info.size), |
| 896 | }, | 969 | }, |
| 897 | }; | 970 | }; |
| 898 | mem.writeIntLittle(u32, code, inst.toU32()); | 971 | mem.writeIntLittle(u32, code, inst.toU32()); |
| ... | @@ -942,8 +1015,10 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -942,8 +1015,10 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 942 | mem.writeIntLittle(u32, self.code.items[rel.offset..][0..4], @bitCast(u32, displacement)); | 1015 | mem.writeIntLittle(u32, self.code.items[rel.offset..][0..4], @bitCast(u32, displacement)); |
| 943 | }, | 1016 | }, |
| 944 | .X86_64_RELOC_TLV => { | 1017 | .X86_64_RELOC_TLV => { |
| 945 | // We need to rewrite the opcode from movq to leaq. | 1018 | if (!is_via_thread_ptrs) { |
| 946 | self.code.items[rel.offset - 2] = 0x8d; | 1019 | // We need to rewrite the opcode from movq to leaq. |
| | 1020 | self.code.items[rel.offset - 2] = 0x8d; |
| | 1021 | } |
| 947 | const displacement = try math.cast( | 1022 | const displacement = try math.cast( |
| 948 | i32, | 1023 | i32, |
| 949 | @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4 + rel.addend, | 1024 | @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4 + rel.addend, |