diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index e31619162e..1a315330e3 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -660,6 +660,19 @@ fn resolveRelocInner( // Address of the __got_zig table entry if any. const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file))); + const divExact = struct { + fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 { + return math.divExact(u12, num, den) catch { + try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {s} at offset 0x{x}", .{ + atom.getName(ctx), + r.fmtPretty(ctx.getTarget().cpu.arch), + r.offset, + }); + return error.UnexpectedRemainder; + }; + } + }.divExact; + switch (rel.tag) { .local => relocs_log.debug(" {x}<+{d}>: {s}: [=> {x}] atom({d})", .{ P, @@ -831,12 +844,12 @@ fn resolveRelocInner( }; inst.load_store_register.offset = switch (inst.load_store_register.size) { 0 => if (inst.load_store_register.v == 1) - try math.divExact(u12, @truncate(target), 16) + try divExact(self, rel, @truncate(target), 16, macho_file) else @truncate(target), - 1 => try math.divExact(u12, @truncate(target), 2), - 2 => try math.divExact(u12, @truncate(target), 4), - 3 => try math.divExact(u12, @truncate(target), 8), + 1 => try divExact(self, rel, @truncate(target), 2, macho_file), + 2 => try divExact(self, rel, @truncate(target), 4, macho_file), + 3 => try divExact(self, rel, @truncate(target), 8, macho_file), }; try writer.writeInt(u32, inst.toU32(), .little); } @@ -847,7 +860,7 @@ fn resolveRelocInner( assert(rel.meta.length == 2); assert(!rel.meta.pcrel); const target = math.cast(u64, G + A) orelse return error.Overflow; - aarch64.writeLoadStoreRegInst(try math.divExact(u12, @truncate(target), 8), code[rel_offset..][0..4]); + aarch64.writeLoadStoreRegInst(try divExact(self, rel, @truncate(target), 8, macho_file), code[rel_offset..][0..4]); }, .tlvp_pageoff => { @@ -899,7 +912,7 @@ fn resolveRelocInner( .load_store_register = .{ .rt = reg_info.rd, .rn = reg_info.rn, - .offset = try math.divExact(u12, @truncate(target), 8), + .offset = try divExact(self, rel, @truncate(target), 8, macho_file), .opc = 0b01, .op1 = 0b01, .v = 0, diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig index 2df9355de9..425171a463 100644 --- a/src/link/MachO/Relocation.zig +++ b/src/link/MachO/Relocation.zig @@ -60,6 +60,59 @@ pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool { return lhs.offset < rhs.offset; } +const FormatCtx = struct { Relocation, std.Target.Cpu.Arch }; + +pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatPretty) { + return .{ .data = .{ rel, cpu_arch } }; +} + +fn formatPretty( + ctx: FormatCtx, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + _ = options; + _ = unused_fmt_string; + const rel, const cpu_arch = ctx; + const str = switch (rel.type) { + .signed => "X86_64_RELOC_SIGNED", + .signed1 => "X86_64_RELOC_SIGNED_1", + .signed2 => "X86_64_RELOC_SIGNED_2", + .signed4 => "X86_64_RELOC_SIGNED_4", + .got_load => "X86_64_RELOC_GOT_LOAD", + .tlv => "X86_64_RELOC_TLV", + .zig_got_load => "ZIG_GOT_LOAD", + .page => "ARM64_RELOC_PAGE21", + .pageoff => "ARM64_RELOC_PAGEOFF12", + .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21", + .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12", + .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21", + .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12", + .branch => switch (cpu_arch) { + .x86_64 => "X86_64_RELOC_BRANCH", + .aarch64 => "ARM64_RELOC_BRANCH26", + else => unreachable, + }, + .got => switch (cpu_arch) { + .x86_64 => "X86_64_RELOC_GOT", + .aarch64 => "ARM64_RELOC_POINTER_TO_GOT", + else => unreachable, + }, + .subtractor => switch (cpu_arch) { + .x86_64 => "X86_64_RELOC_SUBTRACTOR", + .aarch64 => "ARM64_RELOC_SUBTRACTOR", + else => unreachable, + }, + .unsigned => switch (cpu_arch) { + .x86_64 => "X86_64_RELOC_UNSIGNED", + .aarch64 => "ARM64_RELOC_UNSIGNED", + else => unreachable, + }, + }; + try writer.writeAll(str); +} + pub const Type = enum { // x86_64 /// RIP-relative displacement (X86_64_RELOC_SIGNED)