Commit 32779a7c73

Jacob Young <jacobly0@users.noreply.github.com>
2025-10-29 21:41:54
aarch64: fix macho external references
1 parent 402c14f
Changed files (2)
src
codegen
src/codegen/aarch64/Mir.zig
@@ -107,6 +107,7 @@ pub fn emit(
         mir.body[nav_reloc.reloc.label],
         body_end - Instruction.size * (1 + nav_reloc.reloc.label),
         nav_reloc.reloc.addend,
+        if (ip.getNav(nav_reloc.nav).getExtern(ip)) |_| .got_load else .direct,
     );
     for (mir.uav_relocs) |uav_reloc| try emitReloc(
         lf,
@@ -124,6 +125,7 @@ pub fn emit(
         mir.body[uav_reloc.reloc.label],
         body_end - Instruction.size * (1 + uav_reloc.reloc.label),
         uav_reloc.reloc.addend,
+        .direct,
     );
     for (mir.lazy_relocs) |lazy_reloc| try emitReloc(
         lf,
@@ -140,6 +142,7 @@ pub fn emit(
         mir.body[lazy_reloc.reloc.label],
         body_end - Instruction.size * (1 + lazy_reloc.reloc.label),
         lazy_reloc.reloc.addend,
+        .direct,
     );
     for (mir.global_relocs) |global_reloc| try emitReloc(
         lf,
@@ -154,6 +157,7 @@ pub fn emit(
         mir.body[global_reloc.reloc.label],
         body_end - Instruction.size * (1 + global_reloc.reloc.label),
         global_reloc.reloc.addend,
+        .direct,
     );
     const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap);
     for (mir.literal_relocs) |literal_reloc| {
@@ -188,6 +192,7 @@ fn emitReloc(
     instruction: Instruction,
     offset: u32,
     addend: u64,
+    kind: enum { direct, got_load },
 ) !void {
     const gpa = zcu.gpa;
     switch (instruction.decode()) {
@@ -198,11 +203,20 @@ fn emitReloc(
             const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
                 else => unreachable,
                 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
-                    .adr => .ADR_PREL_LO21,
-                    .adrp => .ADR_PREL_PG_HI21,
+                    .adr => switch (kind) {
+                        .direct => .ADR_PREL_LO21,
+                        .got_load => unreachable,
+                    },
+                    .adrp => switch (kind) {
+                        .direct => .ADR_PREL_PG_HI21,
+                        .got_load => .ADR_GOT_PAGE,
+                    },
                 },
                 .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
-                    .add => .ADD_ABS_LO12_NC,
+                    .add => switch (kind) {
+                        .direct => .ADD_ABS_LO12_NC,
+                        .got_load => unreachable,
+                    },
                     .sub => unreachable,
                 },
             };
@@ -223,7 +237,10 @@ fn emitReloc(
                         .offset = offset,
                         .target = sym_index,
                         .addend = @bitCast(addend),
-                        .type = .page,
+                        .type = switch (kind) {
+                            .direct => .page,
+                            .got_load => .got_load_page,
+                        },
                         .meta = .{
                             .pcrel = true,
                             .has_subtractor = false,
@@ -238,7 +255,10 @@ fn emitReloc(
                         .offset = offset,
                         .target = sym_index,
                         .addend = @bitCast(addend),
-                        .type = .pageoff,
+                        .type = switch (kind) {
+                            .direct => .pageoff,
+                            .got_load => .got_load_pageoff,
+                        },
                         .meta = .{
                             .pcrel = false,
                             .has_subtractor = false,
@@ -285,20 +305,39 @@ fn emitReloc(
             const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
                 .integer => |integer| switch (integer.decode()) {
                     .unallocated, .prfm => unreachable,
-                    .strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC,
-                    .strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC,
-                    .ldrsw => .LDST32_ABS_LO12_NC,
-                    inline .str, .ldr => |encoded| switch (encoded.sf) {
+                    .strb, .ldrb, .ldrsb => switch (kind) {
+                        .direct => .LDST8_ABS_LO12_NC,
+                        .got_load => unreachable,
+                    },
+                    .strh, .ldrh, .ldrsh => switch (kind) {
+                        .direct => .LDST16_ABS_LO12_NC,
+                        .got_load => unreachable,
+                    },
+                    .ldrsw => switch (kind) {
+                        .direct => .LDST32_ABS_LO12_NC,
+                        .got_load => unreachable,
+                    },
+                    inline .str, .ldr => |encoded, mnemonic| switch (encoded.sf) {
                         .word => .LDST32_ABS_LO12_NC,
-                        .doubleword => .LDST64_ABS_LO12_NC,
+                        .doubleword => switch (kind) {
+                            .direct => .LDST64_ABS_LO12_NC,
+                            .got_load => switch (mnemonic) {
+                                else => comptime unreachable,
+                                .str => unreachable,
+                                .ldr => .LD64_GOT_LO12_NC,
+                            },
+                        },
                     },
                 },
-                .vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) {
-                    .byte => .LDST8_ABS_LO12_NC,
-                    .half => .LDST16_ABS_LO12_NC,
-                    .single => .LDST32_ABS_LO12_NC,
-                    .double => .LDST64_ABS_LO12_NC,
-                    .quad => .LDST128_ABS_LO12_NC,
+                .vector => |vector| switch (kind) {
+                    .direct => switch (vector.group.opc1.decode(vector.group.size)) {
+                        .byte => .LDST8_ABS_LO12_NC,
+                        .half => .LDST16_ABS_LO12_NC,
+                        .single => .LDST32_ABS_LO12_NC,
+                        .double => .LDST64_ABS_LO12_NC,
+                        .quad => .LDST128_ABS_LO12_NC,
+                    },
+                    .got_load => unreachable,
                 },
             };
             try atom.addReloc(gpa, .{
@@ -314,7 +353,10 @@ fn emitReloc(
                 .offset = offset,
                 .target = sym_index,
                 .addend = @bitCast(addend),
-                .type = .pageoff,
+                .type = switch (kind) {
+                    .direct => .pageoff,
+                    .got_load => .got_load_pageoff,
+                },
                 .meta = .{
                     .pcrel = false,
                     .has_subtractor = false,
src/codegen/aarch64/Select.zig
@@ -7257,7 +7257,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
                             .nav = ty_nav.nav,
                             .reloc = .{ .label = @intCast(isel.instructions.items.len) },
                         });
-                        try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
+                        if (ip.getNav(ty_nav.nav).getExtern(ip)) |_|
+                            try isel.emit(.ldr(ptr_ra.x(), .{ .unsigned_offset = .{ .base = ptr_ra.x(), .offset = 0 } }))
+                        else
+                            try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
                         try isel.nav_relocs.append(gpa, .{
                             .nav = ty_nav.nav,
                             .reloc = .{ .label = @intCast(isel.instructions.items.len) },
@@ -10971,7 +10974,10 @@ pub const Value = struct {
                                                         .addend = ptr.byte_offset,
                                                     },
                                                 });
-                                                try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 }));
+                                                if (ip.getNav(nav).getExtern(ip)) |_|
+                                                    try isel.emit(.ldr(mat.ra.x(), .{ .unsigned_offset = .{ .base = mat.ra.x(), .offset = 0 } }))
+                                                else
+                                                    try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 }));
                                                 try isel.nav_relocs.append(zcu.gpa, .{
                                                     .nav = nav,
                                                     .reloc = .{