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 {...@@ -146,10 +146,14 @@ pub const Relocation = struct {
146 is_64bit: bool,146 is_64bit: bool,
147147
148 pub fn resolve(self: Unsigned, args: ResolveArgs) !void {148 pub fn resolve(self: Unsigned, args: ResolveArgs) !void {
149 const result = if (self.subtractor) |subtractor|149 const result = blk: {
150 @intCast(i64, args.target_addr) - @intCast(i64, subtractor.payload.regular.address) + self.addend150 if (self.subtractor) |subtractor| {
151 else151 const sym = args.zld.locals.items[subtractor];
152 @intCast(i64, args.target_addr) + self.addend;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
154 if (self.is_64bit) {158 if (self.is_64bit) {
155 mem.writeIntLittle(u64, args.block.code[args.offset..][0..8], @bitCast(u64, result));159 mem.writeIntLittle(u64, args.block.code[args.offset..][0..8], @bitCast(u64, result));
...@@ -422,7 +426,7 @@ pub const Relocation = struct {...@@ -422,7 +426,7 @@ pub const Relocation = struct {
422 i32,426 i32,
423 target_addr - @intCast(i64, args.source_addr) - self.correction - 4,427 target_addr - @intCast(i64, args.source_addr) - self.correction - 4,
424 );428 );
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));
426 }430 }
427431
428 pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {432 pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
...@@ -442,16 +446,16 @@ pub const Relocation = struct {...@@ -442,16 +446,16 @@ pub const Relocation = struct {
442 },446 },
443 addend: i32 = 0,447 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 {
446 if (self.kind == .tlvp) {450 if (self.kind == .tlvp) {
447 // We need to rewrite the opcode from movq to leaq.451 // We need to rewrite the opcode from movq to leaq.
448 block.code[offset - 2] = 0x8d;452 args.block.code[args.offset - 2] = 0x8d;
449 }453 }
450 const displacement = try math.cast(454 const displacement = try math.cast(
451 i32,455 i32,
452 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + self.addend,456 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + self.addend,
453 );457 );
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));
455 }459 }
456460
457 pub fn format(self: Load, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {461 pub fn format(self: Load, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
...@@ -464,15 +468,15 @@ pub const Relocation = struct {...@@ -464,15 +468,15 @@ pub const Relocation = struct {
464 }468 }
465 };469 };
466470
467 pub fn resolve(self: Relocation, block: *TextBlock, args: ResolveArgs) !void {471 pub fn resolve(self: Relocation, args: ResolveArgs) !void {
468 switch (self.payload) {472 switch (self.payload) {
469 .unsigned => |unsigned| try unsigned.resolve(block, self.offset, args),473 .unsigned => |unsigned| try unsigned.resolve(args),
470 .branch => |branch| try branch.resolve(block, self.offset, args),474 .branch => |branch| try branch.resolve(args),
471 .page => |page| try page.resolve(block, self.offset, args),475 .page => |page| try page.resolve(args),
472 .page_off => |page_off| try page_off.resolve(block, self.offset, args),476 .page_off => |page_off| try page_off.resolve(args),
473 .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(block, self.offset, args),477 .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(args),
474 .signed => |signed| try signed.resolve(block, self.offset, args),478 .signed => |signed| try signed.resolve(args),
475 .load => |load| try load.resolve(block, self.offset, args),479 .load => |load| try load.resolve(args),
476 }480 }
477 }481 }
478482
...@@ -983,7 +987,7 @@ fn parseLoad(self: TextBlock, rel: macho.relocation_info, out: *Relocation) void...@@ -983,7 +987,7 @@ fn parseLoad(self: TextBlock, rel: macho.relocation_info, out: *Relocation) void
983987
984pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {988pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
985 for (self.relocs.items) |rel| {989 for (self.relocs.items) |rel| {
986 log.debug("relocating {}", .{rel});990 log.warn("relocating {}", .{rel});
987991
988 const source_addr = blk: {992 const source_addr = blk: {
989 const sym = zld.locals.items[self.local_sym_index];993 const sym = zld.locals.items[self.local_sym_index];
...@@ -1001,20 +1005,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {...@@ -1001,20 +1005,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
1001 if (is_via_got) {1005 if (is_via_got) {
1002 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;1006 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
1003 const got = dc_seg.sections.items[zld.got_section_index.?];1007 const got = dc_seg.sections.items[zld.got_section_index.?];
1004 const got_index = rel.target.got_index orelse {1008 const got_index = zld.got_entries.getIndex(.{
1005 log.err("expected GOT entry for symbol '{s}'", .{zld.getString(rel.target.strx)});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)});
1006 log.err(" this is an internal linker error", .{});1017 log.err(" this is an internal linker error", .{});
1007 return error.FailedToResolveRelocationTarget;1018 return error.FailedToResolveRelocationTarget;
1008 };1019 };
1009 break :blk got.addr + got_index * @sizeOf(u64);1020 break :blk got.addr + got_index * @sizeOf(u64);
1010 }1021 }
10111022
1012 switch (rel.target.payload) {1023 switch (rel.where) {
1013 .regular => |reg| {1024 .local => {
1025 const sym = zld.locals.items[rel.where_index];
1014 const is_tlv = is_tlv: {1026 const is_tlv = is_tlv: {
1015 const sym = zld.locals.items[self.local_sym_index];1027 const sym = zld.locals.items[self.local_sym_index];
1016 const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment;1028 const match = zld.unpackSectionId(sym.n_sect);
1017 const sect = seg.sections.items[sym.payload.regular.section_id];1029 const seg = zld.load_commands.items[match.seg].Segment;
1030 const sect = seg.sections.items[match.sect];
1018 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;1031 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
1019 };1032 };
1020 if (is_tlv) {1033 if (is_tlv) {
...@@ -1036,36 +1049,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {...@@ -1036,36 +1049,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
1036 return error.FailedToResolveRelocationTarget;1049 return error.FailedToResolveRelocationTarget;
1037 }1050 }
1038 };1051 };
1039 break :blk reg.address - base_address;1052 break :blk sym.n_value - base_address;
1040 }1053 }
10411054
1042 break :blk reg.address;1055 break :blk sym.n_value;
1043 },1056 },
1044 .proxy => {1057 .import => {
1045 if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {1058 // TODO I think this will be autohandled by self.bindings.
1046 break :blk 0; // Dynamically bound by dyld.1059 // if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {
1047 }1060 // break :blk 0; // Dynamically bound by dyld.
10481061 // }
1049 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;1062 const stubs_index = zld.stubs.getIndex(rel.where_index) orelse {
1050 const stubs = segment.sections.items[zld.stubs_section_index.?];
1051 const stubs_index = rel.target.stubs_index orelse {
1052 // TODO verify in TextBlock that the symbol is indeed dynamically bound.1063 // TODO verify in TextBlock that the symbol is indeed dynamically bound.
1053 break :blk 0; // Dynamically bound by dyld.1064 break :blk 0; // Dynamically bound by dyld.
1054 };1065 };
1066 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
1067 const stubs = segment.sections.items[zld.stubs_section_index.?];
1055 break :blk stubs.addr + stubs_index * stubs.reserved2;1068 break :blk stubs.addr + stubs_index * stubs.reserved2;
1056 },1069 },
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 },
1064 }1070 }
1065 };1071 };
10661072
1067 log.debug(" | source_addr = 0x{x}", .{source_addr});1073 log.warn(" | source_addr = 0x{x}", .{source_addr});
1068 log.debug(" | target_addr = 0x{x}", .{target_addr});1074 log.warn(" | target_addr = 0x{x}", .{target_addr});
10691075
1070 try rel.resolve(self, source_addr, target_addr);1076 try rel.resolve(self, source_addr, target_addr);
1071 }1077 }