| ... | ... | @@ -146,10 +146,14 @@ pub const Relocation = struct { |
| 146 | 146 | is_64bit: bool, |
| 147 | 147 | |
| 148 | 148 | 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 | }; |
| 153 | 157 | |
| 154 | 158 | if (self.is_64bit) { |
| 155 | 159 | mem.writeIntLittle(u64, args.block.code[args.offset..][0..8], @bitCast(u64, result)); |
| ... | ... | @@ -422,7 +426,7 @@ pub const Relocation = struct { |
| 422 | 426 | i32, |
| 423 | 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 | } |
| 427 | 431 | |
| 428 | 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 | 446 | }, |
| 443 | 447 | addend: i32 = 0, |
| 444 | 448 | |
| 445 | | pub fn resolve(self: Load, block: *TextBlock, offset: u32, args: ResolveArgs) !void { |
| 449 | pub fn resolve(self: Load, args: ResolveArgs) !void { |
| 446 | 450 | if (self.kind == .tlvp) { |
| 447 | 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 | 454 | const displacement = try math.cast( |
| 451 | 455 | i32, |
| 452 | 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 | } |
| 456 | 460 | |
| 457 | 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 | 468 | } |
| 465 | 469 | }; |
| 466 | 470 | |
| 467 | | pub fn resolve(self: Relocation, block: *TextBlock, args: ResolveArgs) !void { |
| 471 | pub fn resolve(self: Relocation, args: ResolveArgs) !void { |
| 468 | 472 | 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), |
| 476 | 480 | } |
| 477 | 481 | } |
| 478 | 482 | |
| ... | ... | @@ -983,7 +987,7 @@ fn parseLoad(self: TextBlock, rel: macho.relocation_info, out: *Relocation) void |
| 983 | 987 | |
| 984 | 988 | pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { |
| 985 | 989 | for (self.relocs.items) |rel| { |
| 986 | | log.debug("relocating {}", .{rel}); |
| 990 | log.warn("relocating {}", .{rel}); |
| 987 | 991 | |
| 988 | 992 | const source_addr = blk: { |
| 989 | 993 | const sym = zld.locals.items[self.local_sym_index]; |
| ... | ... | @@ -1001,20 +1005,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { |
| 1001 | 1005 | if (is_via_got) { |
| 1002 | 1006 | const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment; |
| 1003 | 1007 | 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)}); |
| 1006 | 1017 | log.err(" this is an internal linker error", .{}); |
| 1007 | 1018 | return error.FailedToResolveRelocationTarget; |
| 1008 | 1019 | }; |
| 1009 | 1020 | break :blk got.addr + got_index * @sizeOf(u64); |
| 1010 | 1021 | } |
| 1011 | 1022 | |
| 1012 | | switch (rel.target.payload) { |
| 1013 | | .regular => |reg| { |
| 1023 | switch (rel.where) { |
| 1024 | .local => { |
| 1025 | const sym = zld.locals.items[rel.where_index]; |
| 1014 | 1026 | const is_tlv = is_tlv: { |
| 1015 | 1027 | 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]; |
| 1018 | 1031 | break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES; |
| 1019 | 1032 | }; |
| 1020 | 1033 | if (is_tlv) { |
| ... | ... | @@ -1036,36 +1049,29 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { |
| 1036 | 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 | } |
| 1041 | 1054 | |
| 1042 | | break :blk reg.address; |
| 1055 | break :blk sym.n_value; |
| 1043 | 1056 | }, |
| 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 { |
| 1052 | 1063 | // TODO verify in TextBlock that the symbol is indeed dynamically bound. |
| 1053 | 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 | 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 | }; |
| 1066 | 1072 | |
| 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}); |
| 1069 | 1075 | |
| 1070 | 1076 | try rel.resolve(self, source_addr, target_addr); |
| 1071 | 1077 | } |