diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-07-17 11:01:10 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-07-17 11:01:10 +0200 |
| commit | db8020ac0d40caec099ef987c5c43ba637f87c97 (patch) | |
| tree | ab88deaca72e4d9570187ebd3561f6f3fded8b94 /src/link/MachO/TextBlock.zig | |
| parent | 407745a5e91685d52189548620d112a4b34c8127 (diff) | |
| download | zig-db8020ac0d40caec099ef987c5c43ba637f87c97.tar.gz zig-db8020ac0d40caec099ef987c5c43ba637f87c97.zip | |
zld: adjust resolving relocs logic to the new approach
Diffstat (limited to 'src/link/MachO/TextBlock.zig')
| -rw-r--r-- | src/link/MachO/TextBlock.zig | 90 |
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); } |
