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 {
15331533 }
15341534 if (rel.target == .section) {
15351535 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;
15371538 }
15381539
15391540 rebases: {
......@@ -1588,7 +1589,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
15881589 else => |tt| {
15891590 if (tt == .signed and rel.target == .section) {
15901591 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;
15921594 }
15931595 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
15941596 },
src/link/MachO/reloc.zig+7-4
......@@ -29,7 +29,8 @@ pub const Relocation = struct {
2929 source_addr: u64,
3030 target_addr: u64,
3131 subtractor: ?u64 = null,
32 source_sect_addr: ?u64 = null,
32 source_source_sect_addr: ?u64 = null,
33 source_target_sect_addr: ?u64 = null,
3334 };
3435
3536 pub fn resolve(base: *Relocation, args: ResolveArgs) !void {
......@@ -39,8 +40,10 @@ pub const Relocation = struct {
3940 log.debug(" | target address 0x{x}", .{args.target_addr});
4041 if (args.subtractor) |sub|
4142 log.debug(" | subtractor address 0x{x}", .{sub});
42 if (args.source_sect_addr) |addr|
43 log.debug(" | source section address 0x{x}", .{addr});
43 if (args.source_source_sect_addr) |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
4548 return switch (base.@"type") {
4649 .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args),
......@@ -104,7 +107,7 @@ pub const Unsigned = struct {
104107
105108 pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void {
106109 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.?)
108111 else
109112 unsigned.addend;
110113
src/link/MachO/reloc/x86_64.zig+15-18
......@@ -33,16 +33,19 @@ pub const Signed = struct {
3333 pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {
3434 const target_addr = target_addr: {
3535 if (signed.base.target == .section) {
36 const source_target = @intCast(i64, signed.base.offset) + signed.addend + 4 + signed.correction;
37 const source_disp = source_target - @intCast(i64, args.source_sect_addr.?);
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_target_sect_addr.?);
3838 break :target_addr @intCast(i64, args.target_addr) + source_disp;
3939 }
4040 break :target_addr @intCast(i64, args.target_addr) + signed.addend;
4141 };
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});
45 log.debug(" | calculated correction 0x{x}", .{signed.correction});
47 log.debug(" | addend 0x{x}", .{signed.addend});
48 log.debug(" | correction 0x{x}", .{signed.correction});
4649 log.debug(" | displacement 0x{x}", .{displacement});
4750
4851 mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement));
......@@ -172,20 +175,14 @@ pub const Parser = struct {
172175
173176 const offset = @intCast(u32, rel.r_address);
174177 const inst = parser.code[offset..][0..4];
175 const addend = mem.readIntLittle(i32, inst);
176
177 const correction: i4 = correction: {
178 if (is_extern) break :correction 0;
179
180 const corr: i4 = switch (rel_type) {
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;
178 const correction: i4 = switch (rel_type) {
179 .X86_64_RELOC_SIGNED => 0,
180 .X86_64_RELOC_SIGNED_1 => 1,
181 .X86_64_RELOC_SIGNED_2 => 2,
182 .X86_64_RELOC_SIGNED_4 => 4,
183 else => unreachable,
188184 };
185 const addend = mem.readIntLittle(i32, inst) + correction;
189186
190187 var signed = try parser.allocator.create(Signed);
191188 errdefer parser.allocator.destroy(signed);