authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-09 16:24:53+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-09 16:24:53+02:00
logf67e756211b6e69cc8fadbb6b1ec5af1bd5c7049
tree69d8704e34a0855ca855de3cf096df26b6b5eced
parent15d6efecfbe8be46e5dbd7765f0ef9726144db5d

zld: adjust signed displacement source target addr

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 }
15381539
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 };
3435
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});
4447
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 {
104107
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 else111 else
109 unsigned.addend;112 unsigned.addend;
110113
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 );
4346
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});
4750
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 {
172175
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) {
176179 .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,
179182 .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;
189186
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);