diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig index cdb9a847d8..d71c410b1d 100644 --- a/src/codegen/aarch64/Mir.zig +++ b/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, diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 8d6ffcce2e..4fe798271f 100644 --- a/src/codegen/aarch64/Select.zig +++ b/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 = .{