zld: fix resolving TLV offset relocations
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user