Commit dd5c7588d1
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: {
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();