diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index a3e322179d..c6b86cce63 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -735,13 +735,12 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void { assert(rel_pos.len > 0); // TODO convert to an error as the FDE eh frame is malformed // Find function symbol that this record describes const rel = relocs[rel_pos.start..][rel_pos.len - 1]; - const target = UnwindInfo.parseRelocTarget( - zld, - object_id, - rel, - it.data[offset..], - @intCast(i32, offset), - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = object_id, + .rel = rel, + .code = it.data[offset..], + .base_offset = @intCast(i32, offset), + }); break :blk target; }, .x86_64 => { @@ -825,13 +824,12 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void { // Find function symbol that this record describes const rel = relocs[rel_pos.start..][rel_pos.len - 1]; - const target = UnwindInfo.parseRelocTarget( - zld, - object_id, - rel, - mem.asBytes(&record), - @intCast(i32, offset), - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = object_id, + .rel = rel, + .code = mem.asBytes(&record), + .base_offset = @intCast(i32, offset), + }); log.debug("unwind record {d} tracks {s}", .{ record_id, zld.getSymbolName(target) }); if (target.getFile() != object_id) { self.unwind_relocs_lookup[record_id].dead = true; diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig index c64e617a35..e59f5fe250 100644 --- a/src/link/MachO/UnwindInfo.zig +++ b/src/link/MachO/UnwindInfo.zig @@ -218,13 +218,12 @@ pub fn scanRelocs(zld: *Zld) !void { record_id, )) |rel| { // Personality function; add GOT pointer. - const target = parseRelocTarget( - zld, - @intCast(u32, object_id), - rel, - mem.asBytes(&record), - @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = @intCast(u32, object_id), + .rel = rel, + .code = mem.asBytes(&record), + .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), + }); try Atom.addGotEntry(zld, target); } } @@ -266,13 +265,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { @intCast(u32, object_id), record_id, )) |rel| { - const target = parseRelocTarget( - zld, - @intCast(u32, object_id), - rel, - mem.asBytes(&record), - @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = @intCast(u32, object_id), + .rel = rel, + .code = mem.asBytes(&record), + .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), + }); const personality_index = info.getPersonalityFunction(target) orelse inner: { const personality_index = info.personalities_count; info.personalities[personality_index] = target; @@ -285,13 +283,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { } if (getLsdaReloc(zld, @intCast(u32, object_id), record_id)) |rel| { - const target = parseRelocTarget( - zld, - @intCast(u32, object_id), - rel, - mem.asBytes(&record), - @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = @intCast(u32, object_id), + .rel = rel, + .code = mem.asBytes(&record), + .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), + }); record.lsda = @bitCast(u64, target); } } @@ -668,41 +665,6 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void { try zld.file.pwriteAll(buffer.items, sect.offset); } -pub fn parseRelocTarget( - zld: *Zld, - object_id: u32, - rel: macho.relocation_info, - code: []const u8, - base_offset: i32, -) SymbolWithLoc { - const tracy = trace(@src()); - defer tracy.end(); - - const object = &zld.objects.items[object_id]; - - const sym_index = if (rel.r_extern == 0) blk: { - const sect_id = @intCast(u8, rel.r_symbolnum - 1); - const rel_offset = @intCast(u32, rel.r_address - base_offset); - assert(rel.r_pcrel == 0 and rel.r_length == 3); - const address_in_section = mem.readIntLittle(u64, code[rel_offset..][0..8]); - const sym_index = object.getSymbolByAddress(address_in_section, sect_id); - break :blk sym_index; - } else object.reverse_symtab_lookup[rel.r_symbolnum]; - - const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id + 1 }; - const sym = zld.getSymbol(sym_loc); - - if (sym.sect() and !sym.ext()) { - // Make sure we are not dealing with a local alias. - const atom_index = object.getAtomIndexForSymbol(sym_index) orelse - return sym_loc; - const atom = zld.getAtom(atom_index); - return atom.getSymbolWithLoc(); - } else if (object.getGlobal(sym_index)) |global_index| { - return zld.globals.items[global_index]; - } else return sym_loc; -} - fn getRelocs(zld: *Zld, object_id: u32, record_id: usize) []const macho.relocation_info { const object = &zld.objects.items[object_id]; assert(object.hasUnwindRecords()); diff --git a/src/link/MachO/ZldAtom.zig b/src/link/MachO/ZldAtom.zig index eb5e1c6ded..c47bce7c17 100644 --- a/src/link/MachO/ZldAtom.zig +++ b/src/link/MachO/ZldAtom.zig @@ -15,6 +15,7 @@ const macho = std.macho; const math = std.math; const mem = std.mem; const meta = std.meta; +const trace = @import("../../tracy.zig").trace; const Allocator = mem.Allocator; const Arch = std.Target.Cpu.Arch; @@ -163,7 +164,7 @@ pub fn scanAtomRelocs(zld: *Zld, atom_index: AtomIndex, relocs: []align(1) const } const RelocContext = struct { - base_addr: u64 = 0, + base_addr: i64 = 0, base_offset: i32 = 0, }; @@ -175,7 +176,7 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext { if (object.getSourceSymbol(atom.sym_index)) |source_sym| { const source_sect = object.getSourceSection(source_sym.n_sect - 1); return .{ - .base_addr = source_sect.addr, + .base_addr = @intCast(i64, source_sect.addr), .base_offset = @intCast(i32, source_sym.n_value - source_sect.addr), }; } @@ -183,55 +184,71 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext { const sect_id = @intCast(u8, atom.sym_index - nbase); const source_sect = object.getSourceSection(sect_id); return .{ - .base_addr = source_sect.addr, + .base_addr = @intCast(i64, source_sect.addr), .base_offset = 0, }; } -pub fn parseRelocTarget(zld: *Zld, atom_index: AtomIndex, rel: macho.relocation_info) SymbolWithLoc { - const atom = zld.getAtom(atom_index); - const object = &zld.objects.items[atom.getFile().?]; +pub fn parseRelocTarget(zld: *Zld, ctx: struct { + object_id: u32, + rel: macho.relocation_info, + code: []const u8, + base_addr: i64 = 0, + base_offset: i32 = 0, +}) SymbolWithLoc { + const tracy = trace(@src()); + defer tracy.end(); - const sym_index = if (rel.r_extern == 0) sym_index: { - const sect_id = @intCast(u8, rel.r_symbolnum - 1); - const ctx = getRelocContext(zld, atom_index); - const atom_code = getAtomCode(zld, atom_index); - const rel_offset = @intCast(u32, rel.r_address - ctx.base_offset); + const object = &zld.objects.items[ctx.object_id]; + log.debug("parsing reloc target in object({d}) '{s}' ", .{ ctx.object_id, object.name }); - const address_in_section = if (rel.r_pcrel == 0) blk: { - break :blk if (rel.r_length == 3) - mem.readIntLittle(u64, atom_code[rel_offset..][0..8]) + const sym_index = if (ctx.rel.r_extern == 0) sym_index: { + const sect_id = @intCast(u8, ctx.rel.r_symbolnum - 1); + const rel_offset = @intCast(u32, ctx.rel.r_address - ctx.base_offset); + + const address_in_section = if (ctx.rel.r_pcrel == 0) blk: { + break :blk if (ctx.rel.r_length == 3) + mem.readIntLittle(u64, ctx.code[rel_offset..][0..8]) else - mem.readIntLittle(u32, atom_code[rel_offset..][0..4]); + mem.readIntLittle(u32, ctx.code[rel_offset..][0..4]); } else blk: { - const correction: u3 = switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) { + assert(zld.options.target.cpu.arch == .x86_64); + const correction: u3 = switch (@intToEnum(macho.reloc_type_x86_64, ctx.rel.r_type)) { .X86_64_RELOC_SIGNED => 0, .X86_64_RELOC_SIGNED_1 => 1, .X86_64_RELOC_SIGNED_2 => 2, .X86_64_RELOC_SIGNED_4 => 4, else => unreachable, }; - const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); - const target_address = @intCast(i64, ctx.base_addr) + rel.r_address + 4 + correction + addend; + const addend = mem.readIntLittle(i32, ctx.code[rel_offset..][0..4]); + const target_address = @intCast(i64, ctx.base_addr) + ctx.rel.r_address + 4 + correction + addend; break :blk @intCast(u64, target_address); }; // Find containing atom + log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id }); const sym_index = object.getSymbolByAddress(address_in_section, sect_id); break :sym_index sym_index; - } else object.reverse_symtab_lookup[rel.r_symbolnum]; + } else object.reverse_symtab_lookup[ctx.rel.r_symbolnum]; - const sym_loc = SymbolWithLoc{ - .sym_index = sym_index, - .file = atom.file, - }; + const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 }; const sym = zld.getSymbol(sym_loc); - - if (sym.sect() and !sym.ext()) { - return sym_loc; - } else if (object.getGlobal(sym_index)) |global_index| { - return zld.globals.items[global_index]; - } else return sym_loc; + const target = target: { + if (sym.sect() and !sym.ext()) { + // Make sure we are not dealing with a local alias. + const atom_index = object.getAtomIndexForSymbol(sym_index) orelse break :target sym_loc; + const atom = zld.getAtom(atom_index); + break :target atom.getSymbolWithLoc(); + } else if (object.getGlobal(sym_index)) |global_index| { + break :target zld.globals.items[global_index]; + } else break :target sym_loc; + }; + log.debug(" | target %{d} ('{s}') in object({?d})", .{ + target.sym_index, + zld.getSymbolName(target), + target.getFile(), + }); + return target; } pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc, is_via_got: bool) ?AtomIndex { @@ -499,13 +516,25 @@ fn resolveRelocsArm64( atom.getFile(), }); - subtractor = parseRelocTarget(zld, atom_index, rel); + subtractor = parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = atom_code, + .base_addr = context.base_addr, + .base_offset = context.base_offset, + }); continue; }, else => {}, } - const target = parseRelocTarget(zld, atom_index, rel); + const target = parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = atom_code, + .base_addr = context.base_addr, + .base_offset = context.base_offset, + }); const rel_offset = @intCast(u32, rel.r_address - context.base_offset); log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{ @@ -781,13 +810,25 @@ fn resolveRelocsX86( atom.getFile(), }); - subtractor = parseRelocTarget(zld, atom_index, rel); + subtractor = parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = atom_code, + .base_addr = context.base_addr, + .base_offset = context.base_offset, + }); continue; }, else => {}, } - const target = parseRelocTarget(zld, atom_index, rel); + const target = parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = atom_code, + .base_addr = context.base_addr, + .base_offset = context.base_offset, + }); const rel_offset = @intCast(u32, rel.r_address - context.base_offset); log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{ diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index a132ecb2de..cd64e72170 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -130,14 +130,29 @@ fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void { const header = zld.sections.items(.header)[sym.n_sect - 1]; if (header.isZerofill()) return; + const code = Atom.getAtomCode(zld, atom_index); const relocs = Atom.getAtomRelocs(zld, atom_index); + const ctx = Atom.getRelocContext(zld, atom_index); + for (relocs) |rel| { const target = switch (cpu_arch) { .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { .ARM64_RELOC_ADDEND => continue, - else => Atom.parseRelocTarget(zld, atom_index, rel), + else => Atom.parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = code, + .base_offset = ctx.base_offset, + .base_addr = ctx.base_addr, + }), }, - .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel), + .x86_64 => Atom.parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = code, + .base_offset = ctx.base_offset, + .base_addr = ctx.base_addr, + }), else => unreachable, }; const target_sym = zld.getSymbol(target); @@ -175,14 +190,29 @@ fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable) bool { const header = zld.sections.items(.header)[sym.n_sect - 1]; assert(!header.isZerofill()); + const code = Atom.getAtomCode(zld, atom_index); const relocs = Atom.getAtomRelocs(zld, atom_index); + const ctx = Atom.getRelocContext(zld, atom_index); + for (relocs) |rel| { const target = switch (cpu_arch) { .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { .ARM64_RELOC_ADDEND => continue, - else => Atom.parseRelocTarget(zld, atom_index, rel), + else => Atom.parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = code, + .base_offset = ctx.base_offset, + .base_addr = ctx.base_addr, + }), }, - .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel), + .x86_64 => Atom.parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = code, + .base_offset = ctx.base_offset, + .base_addr = ctx.base_addr, + }), else => unreachable, }; @@ -283,13 +313,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void { try markEhFrameRecord(zld, object_id, atom_index, alive); } else { if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| { - const target = UnwindInfo.parseRelocTarget( - zld, - object_id, - rel, - mem.asBytes(&record), - @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = object_id, + .rel = rel, + .code = mem.asBytes(&record), + .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), + }); const target_sym = zld.getSymbol(target); if (!target_sym.undf()) { const target_object = zld.objects.items[target.getFile().?]; @@ -299,13 +328,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void { } if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| { - const target = UnwindInfo.parseRelocTarget( - zld, - object_id, - rel, - mem.asBytes(&record), - @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = object_id, + .rel = rel, + .code = mem.asBytes(&record), + .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)), + }); const target_object = zld.objects.items[target.getFile().?]; const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; markLive(zld, target_atom_index, alive); @@ -333,13 +361,12 @@ fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *A // Mark FDE references which should include any referenced LSDA record const relocs = eh_frame.getRelocs(zld, object_id, fde_offset); for (relocs) |rel| { - const target = UnwindInfo.parseRelocTarget( - zld, - object_id, - rel, - fde.data, - @intCast(i32, fde_offset) + 4, - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = object_id, + .rel = rel, + .code = fde.data, + .base_offset = @intCast(i32, fde_offset) + 4, + }); const target_sym = zld.getSymbol(target); if (!target_sym.undf()) blk: { const target_object = zld.objects.items[target.getFile().?]; diff --git a/src/link/MachO/eh_frame.zig b/src/link/MachO/eh_frame.zig index 5420bf6c29..7c5c5b7c25 100644 --- a/src/link/MachO/eh_frame.zig +++ b/src/link/MachO/eh_frame.zig @@ -308,13 +308,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type { }, else => unreachable, } - const target = UnwindInfo.parseRelocTarget( - zld, - object_id, - rel, - rec.data, - @intCast(i32, source_offset) + 4, - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = object_id, + .rel = rel, + .code = rec.data, + .base_offset = @intCast(i32, source_offset) + 4, + }); return target; } return null; @@ -331,13 +330,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type { const relocs = getRelocs(zld, object_id, ctx.source_offset); for (relocs) |rel| { - const target = UnwindInfo.parseRelocTarget( - zld, - object_id, - rel, - rec.data, - @intCast(i32, ctx.source_offset) + 4, - ); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = object_id, + .rel = rel, + .code = rec.data, + .base_offset = @intCast(i32, ctx.source_offset) + 4, + }); const rel_offset = @intCast(u32, rel.r_address - @intCast(i32, ctx.source_offset) - 4); const source_addr = ctx.sect_addr + rel_offset + ctx.out_offset + 4; diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig index ce3fda0b1f..afea08750c 100644 --- a/src/link/MachO/thunks.zig +++ b/src/link/MachO/thunks.zig @@ -225,11 +225,20 @@ fn scanRelocs( break :blk @intCast(i32, source_sym.n_value - source_sect.addr); } else 0; + const code = Atom.getAtomCode(zld, atom_index); const relocs = Atom.getAtomRelocs(zld, atom_index); + const ctx = Atom.getRelocContext(zld, atom_index); + for (relocs) |rel| { if (!relocNeedsThunk(rel)) continue; - const target = Atom.parseRelocTarget(zld, atom_index, rel); + const target = Atom.parseRelocTarget(zld, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = code, + .base_offset = ctx.base_offset, + .base_addr = ctx.base_addr, + }); if (isReachable(zld, atom_index, rel, base_offset, target, allocated)) continue; log.debug("{x}: source = {s}@{x}, target = {s}@{x} unreachable", .{ diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 27a0fa5579..07241b54cd 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -1884,13 +1884,9 @@ pub const Zld = struct { if (should_rebase) { log.debug(" ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) }); - const object = self.objects.items[atom.getFile().?]; - const base_rel_offset: i32 = blk: { - const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0; - const source_sect = object.getSourceSection(source_sym.n_sect - 1); - break :blk @intCast(i32, source_sym.n_value - source_sect.addr); - }; + const code = Atom.getAtomCode(self, atom_index); const relocs = Atom.getAtomRelocs(self, atom_index); + const ctx = Atom.getRelocContext(self, atom_index); for (relocs) |rel| { switch (cpu_arch) { @@ -1906,12 +1902,18 @@ pub const Zld = struct { }, else => unreachable, } - const target = Atom.parseRelocTarget(self, atom_index, rel); + const target = Atom.parseRelocTarget(self, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = code, + .base_offset = ctx.base_offset, + .base_addr = ctx.base_addr, + }); const target_sym = self.getSymbol(target); if (target_sym.undf()) continue; const base_offset = @intCast(i32, sym.n_value - segment.vmaddr); - const rel_offset = rel.r_address - base_rel_offset; + const rel_offset = rel.r_address - ctx.base_offset; const offset = @intCast(u64, base_offset + rel_offset); log.debug(" | rebase at {x}", .{offset}); @@ -2021,13 +2023,9 @@ pub const Zld = struct { }; if (should_bind) { - const object = self.objects.items[atom.getFile().?]; - const base_rel_offset: i32 = blk: { - const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0; - const source_sect = object.getSourceSection(source_sym.n_sect - 1); - break :blk @intCast(i32, source_sym.n_value - source_sect.addr); - }; + const code = Atom.getAtomCode(self, atom_index); const relocs = Atom.getAtomRelocs(self, atom_index); + const ctx = Atom.getRelocContext(self, atom_index); for (relocs) |rel| { switch (cpu_arch) { @@ -2044,15 +2042,20 @@ pub const Zld = struct { else => unreachable, } - const global = Atom.parseRelocTarget(self, atom_index, rel); + const global = Atom.parseRelocTarget(self, .{ + .object_id = atom.getFile().?, + .rel = rel, + .code = code, + .base_offset = ctx.base_offset, + .base_addr = ctx.base_addr, + }); const bind_sym_name = self.getSymbolName(global); const bind_sym = self.getSymbol(global); if (!bind_sym.undf()) continue; const base_offset = sym.n_value - segment.vmaddr; - const rel_offset = @intCast(u32, rel.r_address - base_rel_offset); + const rel_offset = @intCast(u32, rel.r_address - ctx.base_offset); const offset = @intCast(u64, base_offset + rel_offset); - const code = Atom.getAtomCode(self, atom_index); const addend = mem.readIntLittle(i64, code[rel_offset..][0..8]); const dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER);