From e229202cb87a895401f2813f0f12227a0d715c09 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 7 Sep 2021 23:21:08 +0200 Subject: [PATCH] macho: store source section address of relocs in context This is particularly relevant for x86_64 and C++ when relocating StaticInit sections containing static initializers machine code. Then, in case of SIGNED_X relocations, it is necessary to have the full image of the VM address layout of the sections in the object file as this is how the addend needs to be adjusted for non-extern relocations. --- src/link/MachO/Object.zig | 9 ++++++--- src/link/MachO/TextBlock.zig | 23 ++++++++++++----------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index c72aa66b84..d94785b377 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -425,7 +425,8 @@ const TextBlockParser = struct { } try block.parseRelocs(self.relocs, .{ - .base_addr = start_addr, + .base_addr = self.section.addr, + .base_offset = start_addr, .allocator = context.allocator, .object = context.object, .macho_file = context.macho_file, @@ -583,7 +584,8 @@ pub fn parseTextBlocks( } try block.parseRelocs(relocs, .{ - .base_addr = 0, + .base_addr = sect.addr, + .base_offset = 0, .allocator = allocator, .object = self, .macho_file = macho_file, @@ -689,7 +691,8 @@ pub fn parseTextBlocks( } try block.parseRelocs(relocs, .{ - .base_addr = 0, + .base_addr = sect.addr, + .base_offset = 0, .allocator = allocator, .object = self, .macho_file = macho_file, diff --git a/src/link/MachO/TextBlock.zig b/src/link/MachO/TextBlock.zig index 3517e532a0..dca319fedd 100644 --- a/src/link/MachO/TextBlock.zig +++ b/src/link/MachO/TextBlock.zig @@ -479,13 +479,13 @@ pub const Relocation = struct { pub const Signed = struct { addend: i64, - correction: i4, + correction: u3, pub fn resolve(self: Signed, args: ResolveArgs) !void { const target_addr = @intCast(i64, args.target_addr) + self.addend; const displacement = try math.cast( i32, - target_addr - @intCast(i64, args.source_addr) - self.correction - 4, + target_addr - @intCast(i64, args.source_addr + self.correction + 4), ); mem.writeIntLittle(u32, args.block.code.items[args.offset..][0..4], @bitCast(u32, displacement)); } @@ -613,6 +613,7 @@ pub fn freeListEligible(self: TextBlock, macho_file: MachO) bool { const RelocContext = struct { base_addr: u64 = 0, + base_offset: u64 = 0, allocator: *Allocator, object: *Object, macho_file: *MachO, @@ -620,7 +621,7 @@ const RelocContext = struct { fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation { var parsed_rel = Relocation{ - .offset = @intCast(u32, @intCast(u64, rel.r_address) - context.base_addr), + .offset = @intCast(u32, @intCast(u64, rel.r_address) - context.base_offset), .where = undefined, .where_index = undefined, .payload = undefined, @@ -684,7 +685,7 @@ fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Reloc } pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: RelocContext) !void { - const filtered_relocs = filterRelocs(relocs, context.base_addr, context.base_addr + self.size); + const filtered_relocs = filterRelocs(relocs, context.base_offset, context.base_offset + self.size); var it = RelocIterator{ .buffer = filtered_relocs, }; @@ -956,9 +957,9 @@ fn parseUnsigned( mem.readIntLittle(i32, self.code.items[out.offset..][0..4]); if (rel.r_extern == 0) { - const source_seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; - const source_sect_base_addr = source_seg.sections.items[rel.r_symbolnum - 1].addr; - addend -= @intCast(i64, source_sect_base_addr); + const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; + const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; + addend -= @intCast(i64, target_sect_base_addr); } out.payload = .{ @@ -1043,7 +1044,7 @@ fn parseSigned(self: TextBlock, rel: macho.relocation_info, out: *Relocation, co assert(rel.r_length == 2); const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); - const correction: i4 = switch (rel_type) { + const correction: u3 = switch (rel_type) { .X86_64_RELOC_SIGNED => 0, .X86_64_RELOC_SIGNED_1 => 1, .X86_64_RELOC_SIGNED_2 => 2, @@ -1053,9 +1054,9 @@ fn parseSigned(self: TextBlock, rel: macho.relocation_info, out: *Relocation, co var addend: i64 = mem.readIntLittle(i32, self.code.items[out.offset..][0..4]) + correction; if (rel.r_extern == 0) { - const source_seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; - const source_sect_base_addr = source_seg.sections.items[rel.r_symbolnum - 1].addr; - addend = @intCast(i64, out.offset) + addend - @intCast(i64, source_sect_base_addr) + 4 + correction; + const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; + const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; + addend += @intCast(i64, context.base_addr + out.offset + correction + 4) - @intCast(i64, target_sect_base_addr); } out.payload = .{