| ... | @@ -146,10 +146,14 @@ pub const Relocation = struct { | ... | @@ -146,10 +146,14 @@ pub const Relocation = struct { |
| 146 | is_64bit: bool, | 146 | is_64bit: bool, |
| 147 | | 147 | |
| 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.addend | 150 | if (self.subtractor) |subtractor| { |
| 151 | else | 151 | 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 | }; |
| 153 | | 157 | |
| 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 | } |
| 427 | | 431 | |
| 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, |
| 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 | 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 | } |
| 456 | | 460 | |
| 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 | }; |
| 466 | | 470 | |
| 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 | } |
| 478 | | 482 | |
| ... | @@ -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 |
| 983 | | 987 | |
| 984 | pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { | 988 | pub 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}); |
| 987 | | 991 | |
| 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 | } |
| 1011 | | 1022 | |
| 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 | } |
| 1041 | | 1054 | |
| 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. |
| 1048 | | 1061 | // } |
| 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 | }; |
| 1066 | | 1072 | |
| 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}); |
| 1069 | | 1075 | |
| 1070 | try rel.resolve(self, source_addr, target_addr); | 1076 | try rel.resolve(self, source_addr, target_addr); |
| 1071 | } | 1077 | } |