From 1f6165f6211885d3f5392cdfcc15f990284159de Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 12 Apr 2023 10:43:42 +0200 Subject: [PATCH] macho: reference TLV thunks via GOT table --- src/link/MachO.zig | 90 +++++++++++------------------------ src/link/MachO/Relocation.zig | 60 ++++------------------- 2 files changed, 37 insertions(+), 113 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index b958e64e58..0ffb72f087 100644 --- a/src/link/MachO.zig +++ b/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 { diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig index 06a255ad59..81340b1120 100644 --- a/src/link/MachO/Relocation.zig +++ b/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. } }