| author | |
| committer | |
| log | f67e756211b6e69cc8fadbb6b1ec5af1bd5c7049 |
| tree | 69d8704e34a0855ca855de3cf096df26b6b5eced |
| parent | 15d6efecfbe8be46e5dbd7765f0ef9726144db5d |
Previously, I mistakenly assumed that offset of the relocation
is enough when calculating relative offset of the target from the
source target section base address in case of section-based relocs
on x86_64. While this is true for `__TEXT,__text` section which
always starts at 0x0 in object files, this is absolutely not true
for `__TEXT,__StaticInit` section which will have nonzero base
address hence resulting in incorrect displacement calculations for
SIGNED relocs.3 files changed, 26 insertions(+), 24 deletions(-)
src/link/MachO/Zld.zig+4-2| ... | @@ -1533,7 +1533,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1533,7 +1533,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1533 | } | 1533 | } |
| 1534 | if (rel.target == .section) { | 1534 | if (rel.target == .section) { |
| 1535 | const source_sect = object.sections.items[rel.target.section]; | 1535 | const source_sect = object.sections.items[rel.target.section]; |
| 1536 | args.source_sect_addr = source_sect.inner.addr; | 1536 | args.source_source_sect_addr = sect.inner.addr; |
| 1537 | args.source_target_sect_addr = source_sect.inner.addr; | ||
| 1537 | } | 1538 | } |
| 1538 | 1539 | ||
| 1539 | rebases: { | 1540 | rebases: { |
| ... | @@ -1588,7 +1589,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1588,7 +1589,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1588 | else => |tt| { | 1589 | else => |tt| { |
| 1589 | if (tt == .signed and rel.target == .section) { | 1590 | if (tt == .signed and rel.target == .section) { |
| 1590 | const source_sect = object.sections.items[rel.target.section]; | 1591 | const source_sect = object.sections.items[rel.target.section]; |
| 1591 | args.source_sect_addr = source_sect.inner.addr; | 1592 | args.source_source_sect_addr = sect.inner.addr; |
| 1593 | args.source_target_sect_addr = source_sect.inner.addr; | ||
| 1592 | } | 1594 | } |
| 1593 | args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target); | 1595 | args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target); |
| 1594 | }, | 1596 | }, |
src/link/MachO/reloc.zig+7-4| ... | @@ -29,7 +29,8 @@ pub const Relocation = struct { | ... | @@ -29,7 +29,8 @@ pub const Relocation = struct { |
| 29 | source_addr: u64, | 29 | source_addr: u64, |
| 30 | target_addr: u64, | 30 | target_addr: u64, |
| 31 | subtractor: ?u64 = null, | 31 | subtractor: ?u64 = null, |
| 32 | source_sect_addr: ?u64 = null, | 32 | source_source_sect_addr: ?u64 = null, |
| 33 | source_target_sect_addr: ?u64 = null, | ||
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | pub fn resolve(base: *Relocation, args: ResolveArgs) !void { | 36 | pub fn resolve(base: *Relocation, args: ResolveArgs) !void { |
| ... | @@ -39,8 +40,10 @@ pub const Relocation = struct { | ... | @@ -39,8 +40,10 @@ pub const Relocation = struct { |
| 39 | log.debug(" | target address 0x{x}", .{args.target_addr}); | 40 | log.debug(" | target address 0x{x}", .{args.target_addr}); |
| 40 | if (args.subtractor) |sub| | 41 | if (args.subtractor) |sub| |
| 41 | log.debug(" | subtractor address 0x{x}", .{sub}); | 42 | log.debug(" | subtractor address 0x{x}", .{sub}); |
| 42 | if (args.source_sect_addr) |addr| | 43 | if (args.source_source_sect_addr) |addr| |
| 43 | log.debug(" | source section address 0x{x}", .{addr}); | 44 | log.debug(" | source source section address 0x{x}", .{addr}); |
| 45 | if (args.source_target_sect_addr) |addr| | ||
| 46 | log.debug(" | source target section address 0x{x}", .{addr}); | ||
| 44 | 47 | ||
| 45 | return switch (base.@"type") { | 48 | return switch (base.@"type") { |
| 46 | .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args), | 49 | .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args), |
| ... | @@ -104,7 +107,7 @@ pub const Unsigned = struct { | ... | @@ -104,7 +107,7 @@ pub const Unsigned = struct { |
| 104 | 107 | ||
| 105 | pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void { | 108 | pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void { |
| 106 | const addend = if (unsigned.base.target == .section) | 109 | const addend = if (unsigned.base.target == .section) |
| 107 | unsigned.addend - @intCast(i64, args.source_sect_addr.?) | 110 | unsigned.addend - @intCast(i64, args.source_target_sect_addr.?) |
| 108 | else | 111 | else |
| 109 | unsigned.addend; | 112 | unsigned.addend; |
| 110 | 113 |
src/link/MachO/reloc/x86_64.zig+15-18| ... | @@ -33,16 +33,19 @@ pub const Signed = struct { | ... | @@ -33,16 +33,19 @@ pub const Signed = struct { |
| 33 | pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void { | 33 | pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void { |
| 34 | const target_addr = target_addr: { | 34 | const target_addr = target_addr: { |
| 35 | if (signed.base.target == .section) { | 35 | if (signed.base.target == .section) { |
| 36 | const source_target = @intCast(i64, signed.base.offset) + signed.addend + 4 + signed.correction; | 36 | const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4; |
| 37 | const source_disp = source_target - @intCast(i64, args.source_sect_addr.?); | 37 | const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?); |
| 38 | break :target_addr @intCast(i64, args.target_addr) + source_disp; | 38 | break :target_addr @intCast(i64, args.target_addr) + source_disp; |
| 39 | } | 39 | } |
| 40 | break :target_addr @intCast(i64, args.target_addr) + signed.addend; | 40 | break :target_addr @intCast(i64, args.target_addr) + signed.addend; |
| 41 | }; | 41 | }; |
| 42 | const displacement = try math.cast(i32, target_addr - @intCast(i64, args.source_addr) - signed.correction - 4); | 42 | const displacement = try math.cast( |
| 43 | i32, | ||
| 44 | target_addr - @intCast(i64, args.source_addr) - signed.correction - 4, | ||
| 45 | ); | ||
| 43 | 46 | ||
| 44 | log.debug(" | calculated addend 0x{x}", .{signed.addend}); | 47 | log.debug(" | addend 0x{x}", .{signed.addend}); |
| 45 | log.debug(" | calculated correction 0x{x}", .{signed.correction}); | 48 | log.debug(" | correction 0x{x}", .{signed.correction}); |
| 46 | log.debug(" | displacement 0x{x}", .{displacement}); | 49 | log.debug(" | displacement 0x{x}", .{displacement}); |
| 47 | 50 | ||
| 48 | mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement)); | 51 | mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement)); |
| ... | @@ -172,20 +175,14 @@ pub const Parser = struct { | ... | @@ -172,20 +175,14 @@ pub const Parser = struct { |
| 172 | 175 | ||
| 173 | const offset = @intCast(u32, rel.r_address); | 176 | const offset = @intCast(u32, rel.r_address); |
| 174 | const inst = parser.code[offset..][0..4]; | 177 | const inst = parser.code[offset..][0..4]; |
| 175 | const addend = mem.readIntLittle(i32, inst); | 178 | const correction: i4 = switch (rel_type) { |
| 176 | 179 | .X86_64_RELOC_SIGNED => 0, | |
| 177 | const correction: i4 = correction: { | 180 | .X86_64_RELOC_SIGNED_1 => 1, |
| 178 | if (is_extern) break :correction 0; | 181 | .X86_64_RELOC_SIGNED_2 => 2, |
| 179 | 182 | .X86_64_RELOC_SIGNED_4 => 4, | |
| 180 | const corr: i4 = switch (rel_type) { | 183 | else => unreachable, |
| 181 | .X86_64_RELOC_SIGNED => 0, | ||
| 182 | .X86_64_RELOC_SIGNED_1 => 1, | ||
| 183 | .X86_64_RELOC_SIGNED_2 => 2, | ||
| 184 | .X86_64_RELOC_SIGNED_4 => 4, | ||
| 185 | else => unreachable, | ||
| 186 | }; | ||
| 187 | break :correction corr; | ||
| 188 | }; | 184 | }; |
| 185 | const addend = mem.readIntLittle(i32, inst) + correction; | ||
| 189 | 186 | ||
| 190 | var signed = try parser.allocator.create(Signed); | 187 | var signed = try parser.allocator.create(Signed); |
| 191 | errdefer parser.allocator.destroy(signed); | 188 | errdefer parser.allocator.destroy(signed); |