aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-07-17 11:01:10 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-07-17 11:01:10 +0200
commitdb8020ac0d40caec099ef987c5c43ba637f87c97 (patch)
treeab88deaca72e4d9570187ebd3561f6f3fded8b94 /src
parent407745a5e91685d52189548620d112a4b34c8127 (diff)
downloadzig-db8020ac0d40caec099ef987c5c43ba637f87c97.tar.gz
zig-db8020ac0d40caec099ef987c5c43ba637f87c97.zip
zld: adjust resolving relocs logic to the new approach
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO/TextBlock.zig90
1 files changed, 48 insertions, 42 deletions
diff --git a/src/link/MachO/TextBlock.zig b/src/link/MachO/TextBlock.zig
index 20283dfc9d..a76263954f 100644
--- a/src/link/MachO/TextBlock.zig
+++ b/src/link/MachO/TextBlock.zig
@@ -146,10 +146,14 @@ pub const Relocation = struct {
is_64bit: bool,
pub fn resolve(self: Unsigned, args: ResolveArgs) !void {
- const result = if (self.subtractor) |subtractor|
- @intCast(i64, args.target_addr) - @intCast(i64, subtractor.payload.regular.address) + self.addend
- else
- @intCast(i64, args.target_addr) + self.addend;
+ const result = blk: {
+ if (self.subtractor) |subtractor| {
+ const sym = args.zld.locals.items[subtractor];
+ break :blk @intCast(i64, args.target_addr) - @intCast(i64, sym.n_value) + self.addend;
+ } else {
+ break :blk @intCast(i64, args.target_addr) + self.addend;
+ }
+ };
if (self.is_64bit) {
mem.writeIntLittle(u64, args.block.code[args.offset..][0..8], @bitCast(u64, result));
@@ -422,7 +426,7 @@ pub const Relocation = struct {
i32,
target_addr - @intCast(i64, args.source_addr) - self.correction - 4,
);
- mem.writeIntLittle(u32, block.code[offset..][0..4], @bitCast(u32, displacement));
+ mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, displacement));
}
pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
@@ -442,16 +446,16 @@ pub const Relocation = struct {
},
addend: i32 = 0,
- pub fn resolve(self: Load, block: *TextBlock, offset: u32, args: ResolveArgs) !void {
+ pub fn resolve(self: Load, args: ResolveArgs) !void {
if (self.kind == .tlvp) {
// We need to rewrite the opcode from movq to leaq.
- block.code[offset - 2] = 0x8d;
+ args.block.code[args.offset - 2] = 0x8d;
}
const displacement = try math.cast(
i32,
@intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + self.addend,
);
- mem.writeIntLittle(u32, block.code[offset..][0..4], @bitCast(u32, displacement));
+ mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, displacement));
}
pub fn format(self: Load, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
@@ -464,15 +468,15 @@ pub const Relocation = struct {
}
};
- pub fn resolve(self: Relocation, block: *TextBlock, args: ResolveArgs) !void {
+ pub fn resolve(self: Relocation, args: ResolveArgs) !void {
switch (self.payload) {
- .unsigned => |unsigned| try unsigned.resolve(block, self.offset, args),
- .branch => |branch| try branch.resolve(block, self.offset, args),
- .page => |page| try page.resolve(block, self.offset, args),
- .page_off => |page_off| try page_off.resolve(block, self.offset, args),
- .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(block, self.offset, args),
- .signed => |signed| try signed.resolve(block, self.offset, args),
- .load => |load| try load.resolve(block, self.offset, args),
+ .unsigned => |unsigned| try unsigned.resolve(args),
+ .branch => |branch| try branch.resolve(args),
+ .page => |page| try page.resolve(args),
+ .page_off => |page_off| try page_off.resolve(args),
+ .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(args),
+ .signed => |signed| try signed.resolve(args),
+ .load => |load| try load.resolve(args),
}
}
@@ -983,7 +987,7 @@ fn parseLoad(self: TextBlock, rel: macho.relocation_info, out: *Relocation) void
pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
for (self.relocs.items) |rel| {
- log.debug("relocating {}", .{rel});
+ log.warn("relocating {}", .{rel});
const source_addr = blk: {
const sym = zld.locals.items[self.local_sym_index];
@@ -1001,20 +1005,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
if (is_via_got) {
const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
const got = dc_seg.sections.items[zld.got_section_index.?];
- const got_index = rel.target.got_index orelse {
- log.err("expected GOT entry for symbol '{s}'", .{zld.getString(rel.target.strx)});
+ const got_index = zld.got_entries.getIndex(.{
+ .where = rel.where,
+ .where_index = rel.where_index,
+ }) orelse {
+ const sym = switch (rel.where) {
+ .local => zld.locals.items[rel.where_index],
+ .import => zld.imports.items[rel.where_index],
+ };
+ log.err("expected GOT entry for symbol '{s}'", .{zld.getString(sym.n_strx)});
log.err(" this is an internal linker error", .{});
return error.FailedToResolveRelocationTarget;
};
break :blk got.addr + got_index * @sizeOf(u64);
}
- switch (rel.target.payload) {
- .regular => |reg| {
+ switch (rel.where) {
+ .local => {
+ const sym = zld.locals.items[rel.where_index];
const is_tlv = is_tlv: {
const sym = zld.locals.items[self.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];
+ const match = zld.unpackSectionId(sym.n_sect);
+ const seg = zld.load_commands.items[match.seg].Segment;
+ const sect = seg.sections.items[match.sect];
break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
};
if (is_tlv) {
@@ -1036,36 +1049,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
return error.FailedToResolveRelocationTarget;
}
};
- break :blk reg.address - base_address;
+ break :blk sym.n_value - base_address;
}
- break :blk reg.address;
+ break :blk sym.n_value;
},
- .proxy => {
- if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {
- break :blk 0; // Dynamically bound by dyld.
- }
-
- const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
- const stubs = segment.sections.items[zld.stubs_section_index.?];
- const stubs_index = rel.target.stubs_index orelse {
+ .import => {
+ // TODO I think this will be autohandled by self.bindings.
+ // if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {
+ // break :blk 0; // Dynamically bound by dyld.
+ // }
+ const stubs_index = zld.stubs.getIndex(rel.where_index) orelse {
// TODO verify in TextBlock that the symbol is indeed dynamically bound.
break :blk 0; // Dynamically bound by dyld.
};
+ const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
+ const stubs = segment.sections.items[zld.stubs_section_index.?];
break :blk stubs.addr + stubs_index * stubs.reserved2;
},
- else => {
- log.err("failed to resolve symbol '{s}' as a relocation target", .{
- zld.getString(rel.target.strx),
- });
- log.err(" this is an internal linker error", .{});
- return error.FailedToResolveRelocationTarget;
- },
}
};
- log.debug(" | source_addr = 0x{x}", .{source_addr});
- log.debug(" | target_addr = 0x{x}", .{target_addr});
+ log.warn(" | source_addr = 0x{x}", .{source_addr});
+ log.warn(" | target_addr = 0x{x}", .{target_addr});
try rel.resolve(self, source_addr, target_addr);
}