diff --git a/cranelift/codegen/meta/src/isa/arm64.rs b/cranelift/codegen/meta/src/isa/arm64.rs index 5fd7b69309d6..7fc17738bb27 100644 --- a/cranelift/codegen/meta/src/isa/arm64.rs +++ b/cranelift/codegen/meta/src/isa/arm64.rs @@ -5,7 +5,45 @@ use crate::shared::Definitions as SharedDefinitions; fn define_settings(_shared: &SettingGroup) -> SettingGroup { let mut setting = SettingGroupBuilder::new("arm64"); - let has_lse = setting.add_bool("has_lse", "Has Large System Extensions support.", "", false); + let has_lse = setting.add_bool( + "has_lse", + "Has Large System Extensions (FEAT_LSE) support.", + "", + false, + ); + + setting.add_bool( + "has_pauth", + "Has Pointer authentication (FEAT_PAuth) support; enables the use of \ + non-HINT instructions, but does not have an effect on code generation \ + by itself.", + "", + false, + ); + setting.add_bool( + "sign_return_address_all", + "If function return address signing is enabled, then apply it to all \ + functions; does not have an effect on code generation by itself.", + "", + false, + ); + setting.add_bool( + "sign_return_address", + "Use pointer authentication instructions to sign function return \ + addresses; HINT-space instructions using the A key are generated \ + and simple functions that do not use the stack are not affected \ + unless overridden by other settings.", + "", + false, + ); + setting.add_bool( + "sign_return_address_with_bkey", + "Use the B key with pointer authentication instructions instead of \ + the default A key; does not have an effect on code generation by \ + itself. Some platform ABIs may require this, for example.", + "", + false, + ); setting.add_predicate("use_lse", predicate!(has_lse)); setting.build() diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs index 524740d45be6..054f6d8b4a11 100644 --- a/cranelift/codegen/src/isa/aarch64/abi.rs +++ b/cranelift/codegen/src/isa/aarch64/abi.rs @@ -7,7 +7,7 @@ use crate::ir::MemFlags; use crate::ir::Opcode; use crate::ir::{ExternalName, LibCall, Signature}; use crate::isa; -use crate::isa::aarch64::{inst::EmitState, inst::*}; +use crate::isa::aarch64::{inst::EmitState, inst::*, settings as aarch64_settings}; use crate::isa::unwind::UnwindInst; use crate::machinst::*; use crate::settings; @@ -67,9 +67,13 @@ fn saved_reg_stack_size( /// point for the trait; it is never actually instantiated. pub(crate) struct AArch64MachineDeps; +impl IsaFlags for aarch64_settings::Flags {} + impl ABIMachineSpec for AArch64MachineDeps { type I = Inst; + type F = aarch64_settings::Flags; + fn word_bits() -> u32 { 64 } @@ -377,8 +381,22 @@ impl ABIMachineSpec for AArch64MachineDeps { } } - fn gen_ret(rets: Vec) -> Inst { - Inst::Ret { rets } + fn gen_ret(setup_frame: bool, isa_flags: &aarch64_settings::Flags, rets: Vec) -> Inst { + if isa_flags.sign_return_address() && (setup_frame || isa_flags.sign_return_address_all()) { + let key = if isa_flags.sign_return_address_with_bkey() { + APIKey::B + } else { + APIKey::A + }; + + Inst::AuthenticatedRet { + key, + is_hint: !isa_flags.has_pauth(), + rets, + } + } else { + Inst::Ret { rets } + } } fn gen_add_imm(into_reg: Writable, from_reg: Reg, imm: u32) -> SmallInstVec { @@ -493,19 +511,39 @@ impl ABIMachineSpec for AArch64MachineDeps { } } - fn gen_debug_frame_info( + fn gen_prologue_start( + setup_frame: bool, call_conv: isa::CallConv, flags: &settings::Flags, - _isa_flags: &Vec, + isa_flags: &aarch64_settings::Flags, ) -> SmallInstVec { let mut insts = SmallVec::new(); - if flags.unwind_info() && call_conv.extends_apple_aarch64() { + + if isa_flags.sign_return_address() && (setup_frame || isa_flags.sign_return_address_all()) { + let key = if isa_flags.sign_return_address_with_bkey() { + APIKey::B + } else { + APIKey::A + }; + + insts.push(Inst::Pacisp { key }); + + if flags.unwind_info() { + insts.push(Inst::Unwind { + inst: UnwindInst::Aarch64SetPointerAuth { + return_addresses: true, + }, + }); + } + } else if flags.unwind_info() && call_conv.extends_apple_aarch64() { + // The macOS unwinder seems to require this. insts.push(Inst::Unwind { inst: UnwindInst::Aarch64SetPointerAuth { return_addresses: false, }, }); } + insts } diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index e00712767e60..e81868bccc9f 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -672,6 +672,16 @@ (Ret (rets VecReg)) + ;; A machine return instruction with pointer authentication using SP as the + ;; modifier. This instruction requires pointer authentication support + ;; (FEAT_PAuth) unless `is_hint` is true, in which case it is equivalent to + ;; the combination of a no-op and a return instruction on platforms without + ;; the relevant support. + (AuthenticatedRet + (key APIKey) + (is_hint bool) + (rets VecReg)) + ;; An unconditional branch. (Jump (dest BranchTarget)) @@ -746,6 +756,12 @@ (rd WritableReg) (mem AMode)) + ;; Pointer authentication code for instruction address with modifier in SP; + ;; equivalent to a no-op if Pointer authentication (FEAT_PAuth) is not + ;; supported. + (Pacisp + (key APIKey)) + ;; Marker, no-op in generated code: SP "virtual offset" is adjusted. This ;; controls how AMode::NominalSPOffset args are lowered. (VirtualSPOffsetAdj @@ -1308,6 +1324,13 @@ (Xchg) )) +;; Keys for instruction address PACs +(type APIKey + (enum + (A) + (B) +)) + ;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (decl use_lse () Inst) (extern extractor use_lse use_lse) diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs index 19ba761bbdab..1fef41ce4cbc 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs @@ -2774,6 +2774,19 @@ impl MachInstEmit for Inst { &Inst::Ret { .. } => { sink.put4(0xd65f03c0); } + &Inst::AuthenticatedRet { key, is_hint, .. } => { + let key = match key { + APIKey::A => 0b0, + APIKey::B => 0b1, + }; + + if is_hint { + sink.put4(0xd50323bf | key << 6); // autiasp / autibsp + Inst::Ret { rets: vec![] }.emit(&[], sink, emit_info, state); + } else { + sink.put4(0xd65f0bff | key << 10); // retaa / retab + } + } &Inst::Call { ref info } => { if let Some(s) = state.take_stack_map() { sink.add_stack_map(StackMapExtent::UpcomingBytes(4), s); @@ -3064,6 +3077,14 @@ impl MachInstEmit for Inst { add.emit(&[], sink, emit_info, state); } } + &Inst::Pacisp { key } => { + let key = match key { + APIKey::A => 0b0, + APIKey::B => 0b1, + }; + + sink.put4(0xd503233f | key << 6); + } &Inst::VirtualSPOffsetAdj { offset } => { trace!( "virtual sp offset adjusted by {} -> {}", diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs b/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs index eb458b8f1ae9..2439b96bfaec 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs @@ -38,6 +38,25 @@ fn test_aarch64_binemit() { // // $ echo "mov x1, x2" | aarch64inst.sh insns.push((Inst::Ret { rets: vec![] }, "C0035FD6", "ret")); + insns.push(( + Inst::AuthenticatedRet { + key: APIKey::A, + is_hint: true, + rets: vec![], + }, + "BF2303D5C0035FD6", + "autiasp ; ret", + )); + insns.push(( + Inst::AuthenticatedRet { + key: APIKey::B, + is_hint: false, + rets: vec![], + }, + "FF0F5FD6", + "retab", + )); + insns.push((Inst::Pacisp { key: APIKey::B }, "7F2303D5", "pacibsp")); insns.push((Inst::Nop0, "", "nop-zero-len")); insns.push((Inst::Nop4, "1F2003D5", "nop")); insns.push((Inst::Csdb, "9F2203D5", "csdb")); diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs index 7b57b321576f..d3b141dd70b6 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs @@ -36,9 +36,10 @@ mod emit_tests; // Instructions (top level): definition pub use crate::isa::aarch64::lower::isle::generated_code::{ - ALUOp, ALUOp3, AtomicRMWLoopOp, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode, - FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2, - VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp, + ALUOp, ALUOp3, APIKey, AtomicRMWLoopOp, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, + FpuRoundMode, FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, + VecLanesOp, VecMisc2, VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, + VecShiftImmOp, }; /// A floating-point unit (FPU) operation with two args, a register and an immediate. @@ -982,6 +983,11 @@ fn aarch64_get_operands VReg>(inst: &Inst, collector: &mut Operan collector.reg_use(ret); } } + &Inst::AuthenticatedRet { ref rets, .. } => { + for &ret in rets { + collector.reg_use(ret); + } + } &Inst::Jump { .. } => {} &Inst::Call { ref info, .. } => { collector.reg_uses(&info.uses[..]); @@ -1030,6 +1036,7 @@ fn aarch64_get_operands VReg>(inst: &Inst, collector: &mut Operan collector.reg_def(rd); memarg_operands(mem, collector); } + &Inst::Pacisp { .. } => {} &Inst::VirtualSPOffsetAdj { .. } => {} &Inst::ElfTlsGetAddr { .. } => { @@ -1089,7 +1096,7 @@ impl MachInst for Inst { fn is_term(&self) -> MachTerminator { match self { - &Inst::Ret { .. } => MachTerminator::Ret, + &Inst::Ret { .. } | &Inst::AuthenticatedRet { .. } => MachTerminator::Ret, &Inst::Jump { .. } => MachTerminator::Uncond, &Inst::CondBr { .. } => MachTerminator::Cond, &Inst::IndirectBr { .. } => MachTerminator::Indirect, @@ -2476,6 +2483,18 @@ impl Inst { format!("blr {}", rn) } &Inst::Ret { .. } => "ret".to_string(), + &Inst::AuthenticatedRet { key, is_hint, .. } => { + let key = match key { + APIKey::A => "a", + APIKey::B => "b", + }; + + if is_hint { + "auti".to_string() + key + "sp ; ret" + } else { + "reta".to_string() + key + } + } &Inst::Jump { ref dest } => { let dest = dest.pretty_print(0, allocs); format!("b {}", dest) @@ -2650,6 +2669,14 @@ impl Inst { } ret } + &Inst::Pacisp { key } => { + let key = match key { + APIKey::A => "a", + APIKey::B => "b", + }; + + "paci".to_string() + key + "sp" + } &Inst::VirtualSPOffsetAdj { offset } => { state.virtual_sp_offset += offset; format!("virtual_sp_offset_adjust {}", offset) diff --git a/cranelift/codegen/src/isa/aarch64/mod.rs b/cranelift/codegen/src/isa/aarch64/mod.rs index 90ca9862054b..4d96b80340a4 100644 --- a/cranelift/codegen/src/isa/aarch64/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/mod.rs @@ -14,7 +14,7 @@ use crate::settings as shared_settings; use alloc::{boxed::Box, vec::Vec}; use core::fmt; use regalloc2::MachineEnv; -use target_lexicon::{Aarch64Architecture, Architecture, Triple}; +use target_lexicon::{Aarch64Architecture, Architecture, OperatingSystem, Triple}; // New backend: mod abi; @@ -59,7 +59,7 @@ impl AArch64Backend { flags: shared_settings::Flags, ) -> CodegenResult<(VCode, regalloc2::Output)> { let emit_info = EmitInfo::new(flags.clone()); - let abi = Box::new(abi::AArch64ABICallee::new(func, self)?); + let abi = Box::new(abi::AArch64ABICallee::new(func, self, &self.isa_flags)?); compile::compile::(func, self, abi, &self.machine_env, emit_info) } } @@ -147,6 +147,21 @@ impl TargetIsa for AArch64Backend { #[cfg(feature = "unwind")] fn create_systemv_cie(&self) -> Option { + let is_apple_os = match self.triple.operating_system { + OperatingSystem::Darwin + | OperatingSystem::Ios + | OperatingSystem::MacOSX { .. } + | OperatingSystem::Tvos => true, + _ => false, + }; + + if self.isa_flags.sign_return_address() + && self.isa_flags.sign_return_address_with_bkey() + && !is_apple_os + { + unimplemented!("Specifying that the B key is used with pointer authentication instructions in the CIE is not implemented."); + } + Some(inst::unwind::systemv::create_cie()) } diff --git a/cranelift/codegen/src/isa/s390x/abi.rs b/cranelift/codegen/src/isa/s390x/abi.rs index 75ee9557b602..37a62c6d0e41 100644 --- a/cranelift/codegen/src/isa/s390x/abi.rs +++ b/cranelift/codegen/src/isa/s390x/abi.rs @@ -73,7 +73,7 @@ use crate::ir::MemFlags; use crate::ir::Signature; use crate::ir::Type; use crate::isa; -use crate::isa::s390x::inst::*; +use crate::isa::s390x::{inst::*, settings as s390x_settings}; use crate::isa::unwind::UnwindInst; use crate::machinst::*; use crate::machinst::{RealReg, Reg, RegClass, Writable}; @@ -206,9 +206,13 @@ impl Into for StackAMode { /// point for the trait; it is never actually instantiated. pub struct S390xMachineDeps; +impl IsaFlags for s390x_settings::Flags {} + impl ABIMachineSpec for S390xMachineDeps { type I = Inst; + type F = s390x_settings::Flags; + fn word_bits() -> u32 { 64 } @@ -391,7 +395,7 @@ impl ABIMachineSpec for S390xMachineDeps { } } - fn gen_ret(rets: Vec) -> Inst { + fn gen_ret(_setup_frame: bool, _isa_flags: &s390x_settings::Flags, rets: Vec) -> Inst { Inst::Ret { link: gpr(14), rets, diff --git a/cranelift/codegen/src/isa/s390x/mod.rs b/cranelift/codegen/src/isa/s390x/mod.rs index f474eac058f5..123209b8f96d 100644 --- a/cranelift/codegen/src/isa/s390x/mod.rs +++ b/cranelift/codegen/src/isa/s390x/mod.rs @@ -57,7 +57,7 @@ impl S390xBackend { func: &Function, ) -> CodegenResult<(VCode, regalloc2::Output)> { let emit_info = EmitInfo::new(self.isa_flags.clone()); - let abi = Box::new(abi::S390xABICallee::new(func, self)?); + let abi = Box::new(abi::S390xABICallee::new(func, self, &self.isa_flags)?); compile::compile::(func, self, abi, &self.machine_env, emit_info) } } diff --git a/cranelift/codegen/src/isa/x64/abi.rs b/cranelift/codegen/src/isa/x64/abi.rs index abe6a576bb64..e92e95c399ea 100644 --- a/cranelift/codegen/src/isa/x64/abi.rs +++ b/cranelift/codegen/src/isa/x64/abi.rs @@ -3,7 +3,7 @@ use crate::ir::types::*; use crate::ir::{self, types, ExternalName, LibCall, MemFlags, Opcode, Signature, TrapCode, Type}; use crate::isa; -use crate::isa::{unwind::UnwindInst, x64::inst::*, CallConv}; +use crate::isa::{unwind::UnwindInst, x64::inst::*, x64::settings as x64_settings, CallConv}; use crate::machinst::abi_impl::*; use crate::machinst::*; use crate::settings; @@ -29,9 +29,13 @@ pub(crate) type X64ABICaller = ABICallerImpl; /// Implementation of ABI primitives for x64. pub(crate) struct X64ABIMachineSpec; +impl IsaFlags for x64_settings::Flags {} + impl ABIMachineSpec for X64ABIMachineSpec { type I = Inst; + type F = x64_settings::Flags; + fn word_bits() -> u32 { 64 } @@ -270,7 +274,7 @@ impl ABIMachineSpec for X64ABIMachineSpec { } } - fn gen_ret(rets: Vec) -> Self::I { + fn gen_ret(_setup_frame: bool, _isa_flags: &x64_settings::Flags, rets: Vec) -> Self::I { Inst::ret(rets) } diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 73bab652869c..8c7415d88a40 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -51,7 +51,7 @@ impl X64Backend { // This performs lowering to VCode, register-allocates the code, computes // block layout and finalizes branches. The result is ready for binary emission. let emit_info = EmitInfo::new(flags.clone(), self.x64_flags.clone()); - let abi = Box::new(abi::X64ABICallee::new(&func, self)?); + let abi = Box::new(abi::X64ABICallee::new(&func, self, &self.x64_flags)?); compile::compile::(&func, self, abi, &self.reg_env, emit_info) } } diff --git a/cranelift/codegen/src/machinst/abi_impl.rs b/cranelift/codegen/src/machinst/abi_impl.rs index cd304ca47827..433f8053d050 100644 --- a/cranelift/codegen/src/machinst/abi_impl.rs +++ b/cranelift/codegen/src/machinst/abi_impl.rs @@ -271,6 +271,9 @@ impl StackAMode { } } +/// Trait implemented by machine-specific backend to represent ISA flags. +pub trait IsaFlags: Clone {} + /// Trait implemented by machine-specific backend to provide information about /// register assignments and to allow generating the specific instructions for /// stack loads/saves, prologues/epilogues, etc. @@ -278,6 +281,9 @@ pub trait ABIMachineSpec { /// The instruction type. type I: VCodeInst; + /// The ISA flags type. + type F: IsaFlags; + /// Returns the number of bits in a word, that is 32/64 for 32/64-bit architecture. fn word_bits() -> u32; @@ -340,7 +346,7 @@ pub trait ABIMachineSpec { ) -> Self::I; /// Generate a return instruction. - fn gen_ret(rets: Vec) -> Self::I; + fn gen_ret(setup_frame: bool, isa_flags: &Self::F, rets: Vec) -> Self::I; /// Generate an add-with-immediate. Note that even if this uses a scratch /// register, it must satisfy two requirements: @@ -387,12 +393,14 @@ pub trait ABIMachineSpec { /// Generate a meta-instruction that adjusts the nominal SP offset. fn gen_nominal_sp_adj(amount: i32) -> Self::I; - /// Generates extra unwind instructions for a new frame for this - /// architecture, whether the frame has a prologue sequence or not. - fn gen_debug_frame_info( + /// Generates the mandatory part of the prologue, irrespective of whether + /// the usual frame-setup sequence for this architecture is required or not, + /// e.g. extra unwind instructions. + fn gen_prologue_start( + _setup_frame: bool, _call_conv: isa::CallConv, _flags: &settings::Flags, - _isa_flags: &Vec, + _isa_flags: &Self::F, ) -> SmallInstVec { // By default, generates nothing. smallvec![] @@ -722,7 +730,7 @@ pub struct ABICalleeImpl { /// The settings controlling this function's compilation. flags: settings::Flags, /// The ISA-specific flag values controlling this function's compilation. - isa_flags: Vec, + isa_flags: M::F, /// Whether or not this function is a "leaf", meaning it calls no other /// functions is_leaf: bool, @@ -763,7 +771,7 @@ fn get_special_purpose_param_register( impl ABICalleeImpl { /// Create a new body ABI instance. - pub fn new(f: &ir::Function, isa: &dyn TargetIsa) -> CodegenResult { + pub fn new(f: &ir::Function, isa: &dyn TargetIsa, isa_flags: &M::F) -> CodegenResult { trace!("ABI: func signature {:?}", f.signature); let flags = isa.flags().clone(); @@ -857,7 +865,7 @@ impl ABICalleeImpl { ret_area_ptr: None, call_conv, flags, - isa_flags: isa.isa_flags(), + isa_flags: isa_flags.clone(), is_leaf: f.is_leaf(), stack_limit, probestack_min_frame, @@ -1275,7 +1283,7 @@ impl ABICallee for ABICalleeImpl { } } - M::gen_ret(rets) + M::gen_ret(self.setup_frame, &self.isa_flags, rets) } fn set_num_spillslots(&mut self, slots: usize) { @@ -1399,7 +1407,13 @@ impl ABICallee for ABICalleeImpl { ); insts.extend( - M::gen_debug_frame_info(self.call_conv, &self.flags, &self.isa_flags).into_iter(), + M::gen_prologue_start( + self.setup_frame, + self.call_conv, + &self.flags, + &self.isa_flags, + ) + .into_iter(), ); if self.setup_frame { @@ -1473,7 +1487,7 @@ impl ABICallee for ABICalleeImpl { // This `ret` doesn't need any return registers attached // because we are post-regalloc and don't need to // represent the implicit uses anymore. - insts.push(M::gen_ret(vec![])); + insts.push(M::gen_ret(self.setup_frame, &self.isa_flags, vec![])); trace!("Epilogue: {:?}", insts); insts diff --git a/cranelift/filetests/filetests/isa/aarch64/call-pauth.clif b/cranelift/filetests/filetests/isa/aarch64/call-pauth.clif new file mode 100644 index 000000000000..2181f9e41e7e --- /dev/null +++ b/cranelift/filetests/filetests/isa/aarch64/call-pauth.clif @@ -0,0 +1,30 @@ +test compile precise-output +set unwind_info=false +target aarch64 sign_return_address + +function %f1(i64) -> i64 { + fn0 = %g(i64) -> i64 + +block0(v0: i64): + v1 = call fn0(v0) + return v1 +} + +; paciasp +; stp fp, lr, [sp, #-16]! +; mov fp, sp +; block0: +; ldr x5, 8 ; b 12 ; data TestCase { length: 1, ascii: [103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } + 0 +; blr x5 +; ldp fp, lr, [sp], #16 +; autiasp ; ret + +function %f2(i64, i64) -> i64 { +block0(v0: i64, v1: i64): + v2 = iadd.i64 v0, v1 + return v2 +} + +; block0: +; add x0, x0, x1 +; ret diff --git a/cranelift/native/src/lib.rs b/cranelift/native/src/lib.rs index 5f05c583417d..a21dcb450c2a 100644 --- a/cranelift/native/src/lib.rs +++ b/cranelift/native/src/lib.rs @@ -132,6 +132,14 @@ pub fn builder_with_options(infer_native_flags: bool) -> Result usize { - *(fp as *mut usize).offset(1) + let mut pc = *(fp as *mut usize).offset(1); + + // The return address might be signed, so we need to strip the highest bits + // (where the authentication code might be located) in order to obtain a + // valid address. We use the `XPACLRI` instruction, which is executed as a + // no-op by processors that do not support pointer authentication, so that + // the implementation is backward-compatible and there is no duplication. + // However, this instruction requires the LR register for both its input and + // output. + std::arch::asm!( + "mov lr, {pc}", + "xpaclri", + "mov {pc}, lr", + pc = inout(reg) pc, + out("lr") _, + options(nomem, nostack, preserves_flags, pure), + ); + + pc } pub unsafe fn get_next_older_fp_from_fp(fp: usize) -> usize { *(fp as *mut usize) diff --git a/crates/wasmtime/src/engine.rs b/crates/wasmtime/src/engine.rs index 8d49c4751d76..d7c43713e332 100644 --- a/crates/wasmtime/src/engine.rs +++ b/crates/wasmtime/src/engine.rs @@ -449,6 +449,18 @@ impl Engine { { enabled = match flag { "has_lse" => Some(std::arch::is_aarch64_feature_detected!("lse")), + // No effect on its own, but in order to simplify the code on a + // platform without pointer authentication support we fail if + // "has_pauth" is enabled, but "sign_return_address" is not. + "has_pauth" => Some(std::arch::is_aarch64_feature_detected!("paca")), + // No effect on its own. + "sign_return_address_all" => Some(true), + // The pointer authentication instructions act as a `NOP` when + // unsupported (but keep in mind "has_pauth" as well), so it is + // safe to enable them. + "sign_return_address" => Some(true), + // No effect on its own. + "sign_return_address_with_bkey" => Some(true), // fall through to the very bottom to indicate that support is // not enabled to test whether this feature is enabled on the // host. @@ -582,18 +594,15 @@ mod tests { assert_eq!(engine.config().cache_config.cache_hits(), 1); assert_eq!(engine.config().cache_config.cache_misses(), 1); - // FIXME(#1523) need debuginfo on aarch64 before we run this test there - if !cfg!(target_arch = "aarch64") { - let mut cfg = Config::new(); - cfg.debug_info(true).cache_config_load(&config_path)?; - let engine = Engine::new(&cfg)?; - Module::new(&engine, "(module (func))")?; - assert_eq!(engine.config().cache_config.cache_hits(), 0); - assert_eq!(engine.config().cache_config.cache_misses(), 1); - Module::new(&engine, "(module (func))")?; - assert_eq!(engine.config().cache_config.cache_hits(), 1); - assert_eq!(engine.config().cache_config.cache_misses(), 1); - } + let mut cfg = Config::new(); + cfg.debug_info(true).cache_config_load(&config_path)?; + let engine = Engine::new(&cfg)?; + Module::new(&engine, "(module (func))")?; + assert_eq!(engine.config().cache_config.cache_hits(), 0); + assert_eq!(engine.config().cache_config.cache_misses(), 1); + Module::new(&engine, "(module (func))")?; + assert_eq!(engine.config().cache_config.cache_hits(), 1); + assert_eq!(engine.config().cache_config.cache_misses(), 1); Ok(()) } diff --git a/src/commands/compile.rs b/src/commands/compile.rs index 9b54d3ae74d3..801706aff20a 100644 --- a/src/commands/compile.rs +++ b/src/commands/compile.rs @@ -195,6 +195,14 @@ mod test { "--disable-logging", "--cranelift-enable", "has_lse", + "--cranelift-enable", + "has_pauth", + "--cranelift-enable", + "sign_return_address", + "--cranelift-enable", + "sign_return_address_all", + "--cranelift-enable", + "sign_return_address_with_bkey", "-o", output_path.to_str().unwrap(), input_path.to_str().unwrap(),