Commit 1f6165f621

Jakub Konka <kubkon@jakubkonka.com>
2023-04-12 10:43:42
macho: reference TLV thunks via GOT table
1 parent 094ff60
Changed files (2)
src/link/MachO/Relocation.zig
@@ -15,7 +15,7 @@ pub const Type = enum {
     got,
     /// RIP-relative displacement
     signed,
-    /// RIP-relative displacemen to threadlocal variable descriptor
+    /// RIP-relative displacement to GOT pointer to TLV thunk
     tlv,
 
     // aarch64
@@ -27,10 +27,6 @@ pub const Type = enum {
     page,
     /// Offset to a pointer relative to the start of a page in a section
     pageoff,
-    /// PC-relative distance to target page in TLV section
-    tlv_page,
-    /// Offset to a pointer relative to the start of a page in TLV section
-    tlv_pageoff,
 
     // common
     /// PC/RIP-relative displacement B/BL/CALL
@@ -50,7 +46,12 @@ pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
 pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
     return switch (self.type) {
         .got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target),
-        .tlv, .tlv_page, .tlv_pageoff => macho_file.tlvp_table.getAtomIndex(macho_file, self.target),
+        .tlv => {
+            const thunk_atom_index = macho_file.tlv_table.getAtomIndex(macho_file, self.target) orelse
+                return null;
+            const thunk_atom = macho_file.getAtom(thunk_atom_index);
+            return macho_file.got_table.getAtomIndex(macho_file, thunk_atom.getSymbolWithLoc());
+        },
         .branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|
             index
         else
@@ -109,7 +110,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
             inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
             mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
         },
-        .page, .got_page, .tlv_page => {
+        .page, .got_page => {
             const source_page = @intCast(i32, source_addr >> 12);
             const target_page = @intCast(i32, target_addr >> 12);
             const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
@@ -158,49 +159,6 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
                 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
             }
         },
-        .tlv_pageoff => {
-            const RegInfo = struct {
-                rd: u5,
-                rn: u5,
-                size: u2,
-            };
-            const reg_info: RegInfo = blk: {
-                if (isArithmeticOp(buffer[0..4])) {
-                    const inst = mem.bytesToValue(meta.TagPayload(
-                        aarch64.Instruction,
-                        aarch64.Instruction.add_subtract_immediate,
-                    ), buffer[0..4]);
-                    break :blk .{
-                        .rd = inst.rd,
-                        .rn = inst.rn,
-                        .size = inst.sf,
-                    };
-                } else {
-                    const inst = mem.bytesToValue(meta.TagPayload(
-                        aarch64.Instruction,
-                        aarch64.Instruction.load_store_register,
-                    ), buffer[0..4]);
-                    break :blk .{
-                        .rd = inst.rt,
-                        .rn = inst.rn,
-                        .size = inst.size,
-                    };
-                }
-            };
-            const narrowed = @truncate(u12, @intCast(u64, target_addr));
-            var inst = aarch64.Instruction{
-                .add_subtract_immediate = .{
-                    .rd = reg_info.rd,
-                    .rn = reg_info.rn,
-                    .imm12 = narrowed,
-                    .sh = 0,
-                    .s = 0,
-                    .op = 0,
-                    .sf = @truncate(u1, reg_info.size),
-                },
-            };
-            mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
-        },
         .tlv_initializer, .unsigned => switch (self.length) {
             2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))),
             3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)),
@@ -227,7 +185,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
                 else => unreachable,
             }
         },
-        .got_page, .got_pageoff, .page, .pageoff, .tlv_page, .tlv_pageoff => unreachable, // Invalid target architecture.
+        .got_page, .got_pageoff, .page, .pageoff => unreachable, // Invalid target architecture.
     }
 }
 
src/link/MachO.zig
@@ -137,7 +137,6 @@ got_section_index: ?u8 = null,
 data_const_section_index: ?u8 = null,
 la_symbol_ptr_section_index: ?u8 = null,
 data_section_index: ?u8 = null,
-thread_ptr_section_index: ?u8 = null,
 thread_vars_section_index: ?u8 = null,
 thread_data_section_index: ?u8 = null,
 
@@ -157,7 +156,7 @@ strtab: StringTable(.strtab) = .{},
 
 got_table: SectionTable = .{},
 stubs_table: SectionTable = .{},
-tlvp_table: SectionTable = .{},
+tlv_table: SectionTable = .{},
 
 error_flags: File.ErrorFlags = File.ErrorFlags{},
 
@@ -1741,31 +1740,6 @@ fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.In
     return atom_index;
 }
 
-fn createThreadLocalPointerAtom(self: *MachO, tlv_desc_sym_index: u32) !Atom.Index {
-    const atom_index = try self.createAtom();
-    self.getAtomPtr(atom_index).size = @sizeOf(u64);
-
-    const sym = self.getAtom(atom_index).getSymbolPtr(self);
-    sym.n_type = macho.N_SECT;
-    sym.n_sect = self.thread_ptr_section_index.? + 1;
-    sym.n_value = try self.allocateAtom(atom_index, @sizeOf(u64), @alignOf(u64));
-
-    log.debug("allocated threadlocal pointer atom at 0x{x}", .{sym.n_value});
-
-    try Atom.addRelocation(self, atom_index, .{
-        .type = .unsigned,
-        .target = .{ .sym_index = tlv_desc_sym_index },
-        .offset = 0,
-        .addend = 0,
-        .pcrel = false,
-        .length = 3,
-    });
-    try Atom.addRebase(self, atom_index, 0);
-    try self.writePtrWidthAtom(atom_index);
-
-    return atom_index;
-}
-
 fn createMhExecuteHeaderSymbol(self: *MachO) !void {
     if (self.base.options.output_mode != .Exe) return;
     if (self.getGlobal("__mh_execute_header")) |global| {
@@ -1916,7 +1890,7 @@ pub fn deinit(self: *MachO) void {
 
     self.got_table.deinit(gpa);
     self.stubs_table.deinit(gpa);
-    self.tlvp_table.deinit(gpa);
+    self.tlv_table.deinit(gpa);
     self.strtab.deinit(gpa);
 
     self.locals.deinit(gpa);
@@ -2150,13 +2124,11 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
 }
 
 fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {
-    if (self.tlvp_table.lookup.contains(target)) return;
-    const tlvp_index = try self.tlvp_table.allocateEntry(self.base.allocator, target);
-    const tlv_desc_atom_index = try self.createThreadLocalDescriptorAtom(target);
-    const tlv_desc_atom = self.getAtom(tlv_desc_atom_index);
-    const tlv_ptr_atom_index = try self.createThreadLocalPointerAtom(tlv_desc_atom.getSymbolIndex().?);
-    const tlv_ptr_atom = self.getAtom(tlv_ptr_atom_index);
-    self.tlvp_table.entries.items[tlvp_index].sym_index = tlv_ptr_atom.getSymbolIndex().?;
+    if (self.tlv_table.lookup.contains(target)) return;
+    const tlv_index = try self.tlv_table.allocateEntry(self.base.allocator, target);
+    const tlv_atom_index = try self.createThreadLocalDescriptorAtom(target);
+    const tlv_atom = self.getAtom(tlv_atom_index);
+    self.tlv_table.entries.items[tlv_index].sym_index = tlv_atom.getSymbolIndex().?;
     self.markRelocsDirtyByTarget(target);
 }
 
@@ -2550,18 +2522,18 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
 
             if (vaddr != sym.n_value) {
                 sym.n_value = vaddr;
-                const target = SymbolWithLoc{ .sym_index = sym_index };
+                // TODO: I think we should update the offset to the initializer here too.
+                const target: SymbolWithLoc = if (is_threadlocal) blk: {
+                    const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{
+                        .sym_index = sym_index,
+                    }).?;
+                    const tlv_atom = self.getAtom(tlv_atom_index);
+                    break :blk tlv_atom.getSymbolWithLoc();
+                } else .{ .sym_index = sym_index };
                 self.markRelocsDirtyByTarget(target);
-                if (is_threadlocal) {
-                    @panic("TODO update the threadlocal variable's name also");
-                    // log.debug("  (updating threadlocal pointer entry)", .{});
-                    // const tlvp_atom_index = self.tlvp_table.getAtomIndex(self, target).?;
-                    // try self.writePtrWidthAtom(tlvp_atom_index);
-                } else {
-                    log.debug("  (updating GOT entry)", .{});
-                    const got_atom_index = self.got_table.getAtomIndex(self, target).?;
-                    try self.writePtrWidthAtom(got_atom_index);
-                }
+                log.debug("  (updating GOT entry)", .{});
+                const got_atom_index = self.got_table.getAtomIndex(self, target).?;
+                try self.writePtrWidthAtom(got_atom_index);
             }
         } else if (code_len < atom.size) {
             self.shrinkAtom(atom_index, code_len);
@@ -2586,12 +2558,15 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
         self.getAtomPtr(atom_index).size = code_len;
         sym.n_value = vaddr;
 
-        const target: SymbolWithLoc = .{ .sym_index = sym_index };
         if (is_threadlocal) {
-            try self.addTlvEntry(target);
-        } else {
-            try self.addGotEntry(target);
+            try self.addTlvEntry(.{ .sym_index = sym_index });
         }
+        const target: SymbolWithLoc = if (is_threadlocal) blk: {
+            const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{ .sym_index = sym_index }).?;
+            const tlv_atom = self.getAtom(tlv_atom_index);
+            break :blk tlv_atom.getSymbolWithLoc();
+        } else .{ .sym_index = sym_index };
+        try self.addGotEntry(target);
     }
 
     try self.writeAtom(atom_index, code);
@@ -2927,17 +2902,8 @@ fn populateMissingMetadata(self: *MachO) !void {
     }
 
     if (!self.base.options.single_threaded) {
-        if (self.thread_ptr_section_index == null) {
-            self.thread_ptr_section_index = try self.allocateSection("__DATA2", "__thread_ptrs", .{
-                .size = @sizeOf(u64),
-                .alignment = @alignOf(u64),
-                .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
-                .prot = macho.PROT.READ | macho.PROT.WRITE,
-            });
-            self.segment_table_dirty = true;
-        }
         if (self.thread_vars_section_index == null) {
-            self.thread_vars_section_index = try self.allocateSection("__DATA3", "__thread_vars", .{
+            self.thread_vars_section_index = try self.allocateSection("__DATA2", "__thread_vars", .{
                 .size = @sizeOf(u64) * 3,
                 .alignment = @sizeOf(u64),
                 .flags = macho.S_THREAD_LOCAL_VARIABLES,
@@ -2947,7 +2913,7 @@ fn populateMissingMetadata(self: *MachO) !void {
         }
 
         if (self.thread_data_section_index == null) {
-            self.thread_data_section_index = try self.allocateSection("__DATA4", "__thread_data", .{
+            self.thread_data_section_index = try self.allocateSection("__DATA3", "__thread_data", .{
                 .size = @sizeOf(u64),
                 .alignment = @alignOf(u64),
                 .flags = macho.S_THREAD_LOCAL_REGULAR,
@@ -4361,7 +4327,7 @@ pub fn logSymtab(self: *MachO) void {
     log.debug("{}", .{self.stubs_table.fmtDebug(self)});
 
     log.debug("threadlocal entries:", .{});
-    log.debug("{}", .{self.tlvp_table.fmtDebug(self)});
+    log.debug("{}", .{self.tlv_table.fmtDebug(self)});
 }
 
 pub fn logAtoms(self: *MachO) void {