authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-17 11:01:10+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-17 11:01:10+02:00
logdb8020ac0d40caec099ef987c5c43ba637f87c97
treeab88deaca72e4d9570187ebd3561f6f3fded8b94
parent407745a5e91685d52189548620d112a4b34c8127

zld: adjust resolving relocs logic to the new approach


1 files changed, 48 insertions(+), 42 deletions(-)

src/link/MachO/TextBlock.zig+48-42
......@@ -146,10 +146,14 @@ pub const Relocation = struct {
146146 is_64bit: bool,
147147
148148 pub fn resolve(self: Unsigned, args: ResolveArgs) !void {
149 const result = if (self.subtractor) |subtractor|
150 @intCast(i64, args.target_addr) - @intCast(i64, subtractor.payload.regular.address) + self.addend
151 else
152 @intCast(i64, args.target_addr) + self.addend;
149 const result = blk: {
150 if (self.subtractor) |subtractor| {
151 const sym = args.zld.locals.items[subtractor];
152 break :blk @intCast(i64, args.target_addr) - @intCast(i64, sym.n_value) + self.addend;
153 } else {
154 break :blk @intCast(i64, args.target_addr) + self.addend;
155 }
156 };
153157
154158 if (self.is_64bit) {
155159 mem.writeIntLittle(u64, args.block.code[args.offset..][0..8], @bitCast(u64, result));
......@@ -422,7 +426,7 @@ pub const Relocation = struct {
422426 i32,
423427 target_addr - @intCast(i64, args.source_addr) - self.correction - 4,
424428 );
425 mem.writeIntLittle(u32, block.code[offset..][0..4], @bitCast(u32, displacement));
429 mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, displacement));
426430 }
427431
428432 pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
......@@ -442,16 +446,16 @@ pub const Relocation = struct {
442446 },
443447 addend: i32 = 0,
444448
445 pub fn resolve(self: Load, block: *TextBlock, offset: u32, args: ResolveArgs) !void {
449 pub fn resolve(self: Load, args: ResolveArgs) !void {
446450 if (self.kind == .tlvp) {
447451 // We need to rewrite the opcode from movq to leaq.
448 block.code[offset - 2] = 0x8d;
452 args.block.code[args.offset - 2] = 0x8d;
449453 }
450454 const displacement = try math.cast(
451455 i32,
452456 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + self.addend,
453457 );
454 mem.writeIntLittle(u32, block.code[offset..][0..4], @bitCast(u32, displacement));
458 mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, displacement));
455459 }
456460
457461 pub fn format(self: Load, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
......@@ -464,15 +468,15 @@ pub const Relocation = struct {
464468 }
465469 };
466470
467 pub fn resolve(self: Relocation, block: *TextBlock, args: ResolveArgs) !void {
471 pub fn resolve(self: Relocation, args: ResolveArgs) !void {
468472 switch (self.payload) {
469 .unsigned => |unsigned| try unsigned.resolve(block, self.offset, args),
470 .branch => |branch| try branch.resolve(block, self.offset, args),
471 .page => |page| try page.resolve(block, self.offset, args),
472 .page_off => |page_off| try page_off.resolve(block, self.offset, args),
473 .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(block, self.offset, args),
474 .signed => |signed| try signed.resolve(block, self.offset, args),
475 .load => |load| try load.resolve(block, self.offset, args),
473 .unsigned => |unsigned| try unsigned.resolve(args),
474 .branch => |branch| try branch.resolve(args),
475 .page => |page| try page.resolve(args),
476 .page_off => |page_off| try page_off.resolve(args),
477 .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(args),
478 .signed => |signed| try signed.resolve(args),
479 .load => |load| try load.resolve(args),
476480 }
477481 }
478482
......@@ -983,7 +987,7 @@ fn parseLoad(self: TextBlock, rel: macho.relocation_info, out: *Relocation) void
983987
984988pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
985989 for (self.relocs.items) |rel| {
986 log.debug("relocating {}", .{rel});
990 log.warn("relocating {}", .{rel});
987991
988992 const source_addr = blk: {
989993 const sym = zld.locals.items[self.local_sym_index];
......@@ -1001,20 +1005,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
10011005 if (is_via_got) {
10021006 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
10031007 const got = dc_seg.sections.items[zld.got_section_index.?];
1004 const got_index = rel.target.got_index orelse {
1005 log.err("expected GOT entry for symbol '{s}'", .{zld.getString(rel.target.strx)});
1008 const got_index = zld.got_entries.getIndex(.{
1009 .where = rel.where,
1010 .where_index = rel.where_index,
1011 }) orelse {
1012 const sym = switch (rel.where) {
1013 .local => zld.locals.items[rel.where_index],
1014 .import => zld.imports.items[rel.where_index],
1015 };
1016 log.err("expected GOT entry for symbol '{s}'", .{zld.getString(sym.n_strx)});
10061017 log.err(" this is an internal linker error", .{});
10071018 return error.FailedToResolveRelocationTarget;
10081019 };
10091020 break :blk got.addr + got_index * @sizeOf(u64);
10101021 }
10111022
1012 switch (rel.target.payload) {
1013 .regular => |reg| {
1023 switch (rel.where) {
1024 .local => {
1025 const sym = zld.locals.items[rel.where_index];
10141026 const is_tlv = is_tlv: {
10151027 const sym = zld.locals.items[self.local_sym_index];
1016 const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment;
1017 const sect = seg.sections.items[sym.payload.regular.section_id];
1028 const match = zld.unpackSectionId(sym.n_sect);
1029 const seg = zld.load_commands.items[match.seg].Segment;
1030 const sect = seg.sections.items[match.sect];
10181031 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
10191032 };
10201033 if (is_tlv) {
......@@ -1036,36 +1049,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
10361049 return error.FailedToResolveRelocationTarget;
10371050 }
10381051 };
1039 break :blk reg.address - base_address;
1052 break :blk sym.n_value - base_address;
10401053 }
10411054
1042 break :blk reg.address;
1055 break :blk sym.n_value;
10431056 },
1044 .proxy => {
1045 if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {
1046 break :blk 0; // Dynamically bound by dyld.
1047 }
1048
1049 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
1050 const stubs = segment.sections.items[zld.stubs_section_index.?];
1051 const stubs_index = rel.target.stubs_index orelse {
1057 .import => {
1058 // TODO I think this will be autohandled by self.bindings.
1059 // if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {
1060 // break :blk 0; // Dynamically bound by dyld.
1061 // }
1062 const stubs_index = zld.stubs.getIndex(rel.where_index) orelse {
10521063 // TODO verify in TextBlock that the symbol is indeed dynamically bound.
10531064 break :blk 0; // Dynamically bound by dyld.
10541065 };
1066 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
1067 const stubs = segment.sections.items[zld.stubs_section_index.?];
10551068 break :blk stubs.addr + stubs_index * stubs.reserved2;
10561069 },
1057 else => {
1058 log.err("failed to resolve symbol '{s}' as a relocation target", .{
1059 zld.getString(rel.target.strx),
1060 });
1061 log.err(" this is an internal linker error", .{});
1062 return error.FailedToResolveRelocationTarget;
1063 },
10641070 }
10651071 };
10661072
1067 log.debug(" | source_addr = 0x{x}", .{source_addr});
1068 log.debug(" | target_addr = 0x{x}", .{target_addr});
1073 log.warn(" | source_addr = 0x{x}", .{source_addr});
1074 log.warn(" | target_addr = 0x{x}", .{target_addr});
10691075
10701076 try rel.resolve(self, source_addr, target_addr);
10711077 }