diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index cc94b68a57..9afa5007b7 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -131,7 +131,6 @@ pub const TextBlock = struct { size: u64, alignment: u32, rebases: std.ArrayList(u64), - tlv_offsets: std.ArrayList(TlvOffset), next: ?*TextBlock = null, prev: ?*TextBlock = null, @@ -140,11 +139,6 @@ pub const TextBlock = struct { offset: u64, }; - pub const TlvOffset = struct { - local_sym_index: u32, - offset: u64, - }; - pub fn init(allocator: *Allocator) TextBlock { return .{ .allocator = allocator, @@ -155,7 +149,6 @@ pub const TextBlock = struct { .size = undefined, .alignment = undefined, .rebases = std.ArrayList(u64).init(allocator), - .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(allocator), }; } @@ -170,7 +163,6 @@ pub const TextBlock = struct { self.allocator.free(self.code); self.relocs.deinit(); self.rebases.deinit(); - self.tlv_offsets.deinit(); } pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { @@ -210,9 +202,6 @@ pub const TextBlock = struct { if (self.rebases.items.len > 0) { log.warn(" | rebases: {any}", .{self.rebases.items}); } - if (self.tlv_offsets.items.len > 0) { - log.warn(" | TLV offsets: {any}", .{self.tlv_offsets.items}); - } log.warn(" | size = {}", .{self.size}); log.warn(" | align = {}", .{self.alignment}); } @@ -1120,10 +1109,7 @@ fn writeTextBlocks(self: *Zld) !void { var code = try self.allocator.alloc(u8, sect.size); defer self.allocator.free(code); - if (sect_type == macho.S_ZEROFILL or - sect_type == macho.S_THREAD_LOCAL_ZEROFILL or - sect_type == macho.S_THREAD_LOCAL_VARIABLES) - { + if (sect_type == macho.S_ZEROFILL or sect_type == macho.S_THREAD_LOCAL_ZEROFILL) { mem.set(u8, code, 0); } else { var base_off: u64 = sect.size; @@ -2051,41 +2037,6 @@ fn flush(self: *Zld) !void { sect.offset = 0; } - if (self.tlv_section_index) |index| { - // TODO this should be part of relocation resolution routine. - const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; - const sect = &seg.sections.items[index]; - - const base_addr = if (self.tlv_data_section_index) |i| - seg.sections.items[i].addr - else - seg.sections.items[self.tlv_bss_section_index.?].addr; - - var block: *TextBlock = self.blocks.get(.{ - .seg = self.data_segment_cmd_index.?, - .sect = index, - }) orelse unreachable; - - var buffer = try self.allocator.alloc(u8, @intCast(usize, sect.size)); - defer self.allocator.free(buffer); - _ = try self.file.?.preadAll(buffer, sect.offset); - - while (true) { - for (block.tlv_offsets.items) |tlv_offset| { - const sym = self.locals.items[tlv_offset.local_sym_index]; - assert(sym.payload == .regular); - const offset = sym.payload.regular.address - base_addr; - mem.writeIntLittle(u64, buffer[tlv_offset.offset..][0..@sizeOf(u64)], offset); - } - - if (block.prev) |prev| { - block = prev; - } else break; - } - - try self.file.?.pwriteAll(buffer, sect.offset); - } - try self.writeGotEntries(); try self.setEntryPoint(); try self.writeRebaseInfoTable(); diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index bfb2ee905e..7cf477a703 100644 --- a/src/link/MachO/reloc.zig +++ b/src/link/MachO/reloc.zig @@ -50,7 +50,7 @@ pub const Relocation = struct { source_sect_addr: ?u64 = null, - pub fn resolve(self: Unsigned, base: Relocation, source_addr: u64, target_addr: u64) !void { + pub fn resolve(self: Unsigned, base: Relocation, _: u64, target_addr: u64) !void { const addend = if (self.source_sect_addr) |addr| self.addend - @intCast(i64, addr) else @@ -430,12 +430,43 @@ pub const Relocation = struct { } switch (self.target.payload) { - .regular => |reg| break :blk reg.address, + .regular => |reg| { + const is_tlv = is_tlv: { + const sym = zld.locals.items[self.block.local_sym_index]; + const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment; + const sect = seg.sections.items[sym.payload.regular.section_id]; + break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES; + }; + if (is_tlv) { + // For TLV relocations, the value specified as a relocation is the displacement from the + // TLV initializer (either value in __thread_data or zero-init in __thread_bss) to the first + // defined TLV template init section in the following order: + // * wrt to __thread_data if defined, then + // * wrt to __thread_bss + const seg = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment; + const base_address = inner: { + if (zld.tlv_data_section_index) |i| { + break :inner seg.sections.items[i].addr; + } else if (zld.tlv_bss_section_index) |i| { + break :inner seg.sections.items[i].addr; + } else { + log.err("threadlocal variables present but no initializer sections found", .{}); + log.err(" __thread_data not found", .{}); + log.err(" __thread_bss not found", .{}); + return error.FailedToResolveRelocationTarget; + } + }; + break :blk reg.address - base_address; + } + + break :blk reg.address; + }, .proxy => |proxy| { if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) { - const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment; - const tlv = segment.sections.items[zld.tlv_section_index.?]; - break :blk tlv.addr; + break :blk 0; // Dynamically bound by dyld. + // const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment; + // const tlv = segment.sections.items[zld.tlv_section_index.?]; + // break :blk tlv.addr; } const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment; @@ -677,14 +708,6 @@ pub const Parser = struct { if (should_rebase) { try self.block.rebases.append(out_rel.offset); } - - // TLV is handled via a separate offset mechanism. - if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) { - try self.block.tlv_offsets.append(.{ - .local_sym_index = out_rel.target.payload.regular.local_sym_index, - .offset = out_rel.offset, - }); - } }, } } else if (out_rel.payload == .branch) blk: {