Commit 71bbc5efc9

Jakub Konka <kubkon@jakubkonka.com>
2024-05-23 10:13:05
link/macho: print error message when hitting unexpected remainder error
1 parent 78b441e
Changed files (2)
src
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,
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)