diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index dd0064d34bc4a..64f3748e4952e 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -2,7 +2,8 @@ use gccjit::{LValue, RValue, ToRValue, Type}; use rustc_abi::Primitive::Pointer; use rustc_abi::{self as abi, HasDataLayout}; use rustc_codegen_ssa::traits::{ - BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, + BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, PacMetadata, + StaticCodegenMethods, }; use rustc_middle::mir::Mutability; use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; @@ -229,7 +230,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { None } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { + fn scalar_to_backend_with_pac( + &self, + cv: Scalar, + layout: abi::Scalar, + ty: Type<'gcc>, + _pac: Option, + ) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { Scalar::Int(int) => { @@ -278,7 +285,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } value } - GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), + GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, None), GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index c7a2b92ac139c..b6d7d7a7795e4 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -7,7 +7,9 @@ use gccjit::{ use rustc_abi::{Align, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::errors as ssa_errors; -use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods}; +use rustc_codegen_ssa::traits::{ + BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods, PacMetadata, +}; use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::interpret::Allocation; @@ -403,7 +405,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { get_fn(self, instance) } - fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { + fn get_fn_addr(&self, instance: Instance<'tcx>, _pac: Option) -> RValue<'gcc> { let func_name = self.tcx.symbol_name(instance).name; let func = if let Some(variable) = self.get_declared_value(func_name) { diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1f59d250e08a0..57d6b692e2986 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -9,9 +9,10 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet}; use rustc_span::sym; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector}; +use rustc_target::spec::{Arch, Env, FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; +use crate::common::pauth_fn_attrs; use crate::context::SimpleCx; use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; use crate::llvm::AttributePlace::Function; @@ -605,6 +606,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( } } + if sess.target.env == Env::Pauthtest { + for &ptrauth_attr in pauth_fn_attrs() { + to_add.push(llvm::CreateAttrString(cx.llcx, ptrauth_attr)); + } + } + to_add.extend(target_features_attr(cx, tcx, function_features)); attributes::apply_to_llfn(llfn, Function, &to_add); diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index a7dec13422f46..fce5cf7a4e818 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -25,12 +25,13 @@ use rustc_middle::mono::Visibility; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, Offload}; use rustc_span::Symbol; -use rustc_target::spec::SanitizerSet; +use rustc_target::spec::{Env, SanitizerSet}; use super::ModuleLlvm; use crate::attributes; use crate::builder::Builder; use crate::builder::gpu_offload::OffloadGlobals; +use crate::common::pauth_fn_attrs; use crate::context::CodegenCx; use crate::llvm::{self, Value}; @@ -123,7 +124,14 @@ pub(crate) fn compile_codegen_unit( if let Some(entry) = maybe_create_entry_wrapper::>(&cx, cx.codegen_unit) { - let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerFnAttrs::default()); + let mut attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerFnAttrs::default()); + // For pauthtest make sure that the ptrauth-* attributes are also attached to the + // entry wrapper. + if cx.sess().target.env == Env::Pauthtest { + for &ptrauth_attr in pauth_fn_attrs() { + attrs.push(llvm::CreateAttrString(cx.llcx, ptrauth_attr)); + } + } attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); } @@ -140,6 +148,27 @@ pub(crate) fn compile_codegen_unit( cx.add_objc_module_flags(); } + if cx.sess().target.env == Env::Pauthtest { + // FIXME(jchlanda): In LLVM/Clang, there are also `aarch64-elf-pauthabi-platform` + // and `aarch64-elf-pauthabi-version` module flags. These are emitted into the + // PAuth core info section of the resulting ELF, which the linker uses to enforce + // binary compatibility. + // + // We intentionally do not emit this flags now, since only a subset of pointer + // authentication features is currently supported. By default, the absence of this + // info is treated as compatible with any binary. + // + // Please note, that this would cause compatibility issues when linking against + // fully PAuth-enabled C/C++ binaries. + // + // Link to PAuth core info: + // + if cx.sess().opts.unstable_opts.ptrauth_elf_got { + cx.add_ptrauth_elf_got_flag(); + } + cx.add_ptrauth_sign_personality_flag(); + } + // Finalize code coverage by injecting the coverage map. Note, the coverage map will // also be added to the `llvm.compiler.used` variable, created next. if cx.sess().instrument_coverage() { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 056a0763087a2..c16797ae8aff4 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -7,7 +7,7 @@ pub(crate) mod autodiff; pub(crate) mod gpu_offload; use libc::{c_char, c_uint}; -use rustc_abi::{self as abi, Align, Size, WrappingRange}; +use rustc_abi::{self as abi, Align, CanonAbi, Size, WrappingRange}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; @@ -25,7 +25,7 @@ use rustc_sanitizers::{cfi, kcfi}; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_target::callconv::{FnAbi, PassMode}; -use rustc_target::spec::{Arch, HasTargetSpec, SanitizerSet, Target}; +use rustc_target::spec::{Arch, Env, HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -429,6 +429,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { bundles.push(kcfi_bundle); } + let pauth = self.ptrauth_operand_bundle(llfn, fn_abi); + if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) { + bundles.push(p); + } + let invoke = unsafe { llvm::LLVMBuildInvokeWithOperandBundles( self.llbuilder, @@ -1402,6 +1407,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { bundles.push(kcfi_bundle); } + let pauth = self.ptrauth_operand_bundle(llfn, fn_abi); + if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) { + bundles.push(p); + } + let call = unsafe { llvm::LLVMBuildCallWithOperandBundles( self.llbuilder, @@ -1849,6 +1859,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { bundles.push(kcfi_bundle); } + let pauth = self.ptrauth_operand_bundle(llfn, fn_abi); + if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) { + bundles.push(p); + } + let callbr = unsafe { llvm::LLVMBuildCallBr( self.llbuilder, @@ -1968,6 +1983,39 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { kcfi_bundle } + // Emits pauth operand bundle. + fn ptrauth_operand_bundle( + &mut self, + llfn: &'ll Value, + fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + ) -> Option> { + if self.sess().target.env != Env::Pauthtest { + return None; + } + // Pauthtest only supports extern "C" calls, filter out other ABIs. + if fn_abi?.conv != CanonAbi::C { + return None; + } + // Filter out LLVM intrinsics. + if llvm::get_value_name(llfn).starts_with(b"llvm.") { + return None; + } + + // FIXME(jchlanda) Operand bundles should only be attached to indirect function calls. + // However, function pointer signing is currently performed in `get_fn_addr`, which causes + // the logic to be applied too broadly, including to function values (not just pointers). + // As a result, direct calls using signed function values must also receive operand + // bundles. + // Once this is resolved, we should analyze each call and skip direct calls. See the + // discussion in the rust-lang issue: + let key: u32 = 0; + let discriminator: u64 = 0; + Some(llvm::OperandBundleBox::new( + "ptrauth", + &[self.const_u32(key), self.const_u64(discriminator)], + )) + } + /// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation. #[instrument(level = "debug", skip(self))] pub(crate) fn instrprof_increment( diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index dadf8e9e7d5fa..ba7bc6a133107 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -4,23 +4,81 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, HasDataLayout as _}; +use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hashes::Hash128; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{Instance, TyCtxt}; use rustc_session::cstore::DllImport; +use rustc_target::spec::Env; use tracing::debug; -use crate::consts::const_alloc_to_llvm; +use crate::consts::{IsInitOrFini, IsStatic, const_alloc_to_llvm}; pub(crate) use crate::context::CodegenCx; use crate::context::{GenericCx, SCx}; -use crate::llvm::{self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value}; +use crate::llvm::{ + self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value, const_ptr_auth, +}; + +#[inline] +pub(crate) fn pauth_fn_attrs() -> &'static [&'static str] { + // FIXME(jchlanda) This is not an exhaustive list of all `pauthtest`-related attributes, but + // only those currently supported. The list is expected to grow as additional functionality is + // implemented, particularly for C++ interoperability. + &[ + "aarch64-jump-table-hardening", + "ptrauth-indirect-gotos", + "ptrauth-calls", + "ptrauth-returns", + "ptrauth-auth-traps", + ] +} + +pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( + cx: &CodegenCx<'ll, '_>, + instance: Instance<'tcx>, + llfn: &'ll llvm::Value, + pac: PacMetadata, +) -> &'ll llvm::Value { + if cx.sess().target.env != Env::Pauthtest { + return llfn; + } + + // Only free functions or methods + let def_id = instance.def_id(); + if !matches!(cx.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { + return llfn; + } + // Only C ABI + let abi = cx.tcx.fn_sig(def_id).skip_binder().abi(); + if !matches!(abi, ExternAbi::C { .. }) { + return llfn; + } + // Ignore LLVM intrinsics + if llvm::get_value_name(llfn).starts_with(b"llvm.") { + return llfn; + } + if Some(def_id) == cx.tcx.lang_items().eh_personality() { + return llfn; + } + + let addr_diversity = match pac.addr_diversity { + AddressDiversity::None => None, + AddressDiversity::Real => Some(llfn), + AddressDiversity::Synthetic(val) => { + let llval = cx.const_u64(val); + let llty = cx.val_ty(llfn); + Some(unsafe { llvm::LLVMConstIntToPtr(llval, llty) }) + } + }; + const_ptr_auth(llfn, pac.key, pac.disc, addr_diversity) +} /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". @@ -268,7 +326,13 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { }) } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value { + fn scalar_to_backend_with_pac( + &self, + cv: Scalar, + layout: abi::Scalar, + llty: &'ll Type, + pac: Option, + ) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { Scalar::Int(int) => { @@ -297,8 +361,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.const_bitcast(llval, llty) }; } else { - let init = - const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); + let init = const_alloc_to_llvm( + self, + alloc.inner(), + IsStatic::No, + IsInitOrFini::No, + ); let alloc = alloc.inner(); let value = match alloc.mutability { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), @@ -319,7 +387,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { value } } - GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), + GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, pac), GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx @@ -330,7 +398,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { }), ))) .unwrap_memory(); - let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); + let init = const_alloc_to_llvm( + self, + alloc.inner(), + IsStatic::No, + IsInitOrFini::No, + ); self.static_addr_of_impl(init, alloc.inner().align, None) } GlobalAlloc::Static(def_id) => { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 3514fb145612a..b85ea27b24a6b 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use rustc_abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange}; +use rustc_abi::{Align, ExternAbi, HasDataLayout, Primitive, Scalar, Size, WrappingRange}; use rustc_codegen_ssa::common; use rustc_codegen_ssa::traits::*; use rustc_hir::LangItem; @@ -17,19 +17,30 @@ use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; use rustc_span::Symbol; -use rustc_target::spec::Arch; +use rustc_target::spec::{Arch, Env}; use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; use crate::errors::SymbolAlreadyDefined; -use crate::llvm::{self, Type, Value}; +use crate::llvm::{self, Type, Value, const_ptr_auth}; use crate::type_of::LayoutLlvmExt; use crate::{base, debuginfo}; +/// Indicates whether a value originates from a `static`. +pub(crate) enum IsStatic { + Yes, + No, +} +/// Indicates whether a symbol is part of `.init_array` or `.fini_array`. +pub(crate) enum IsInitOrFini { + Yes, + No, +} pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, alloc: &Allocation, - is_static: bool, + is_static: IsStatic, + is_init_fini: IsInitOrFini, ) -> &'ll Value { // We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or // integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be @@ -38,7 +49,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>( // // Statics have a guaranteed meaningful address so it's less clear that we want to do // something like this; it's also harder. - if !is_static { + if matches!(is_static, IsStatic::No) { assert!(alloc.len() != 0); } let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); @@ -109,14 +120,29 @@ pub(crate) fn const_alloc_to_llvm<'ll>( as u64; let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx); - - llvals.push(cx.scalar_to_backend( + // For aarch64-unknown-linux-pauthtest function pointers stored in init/fini arrays need + // special handling. + let pac_metadata = Some( + if cx.sess().target.env == Env::Pauthtest && matches!(is_init_fini, IsInitOrFini::Yes) { + PacMetadata { + // Must correspond to ptrauth_key_init_fini_pointer from `ptrauth.h`. + key: 0, + // ptrauth_string_discriminator("init_fini") + disc: 0xd9d4, + addr_diversity: AddressDiversity::Synthetic(1), + } + } else { + PacMetadata::default() + }, + ); + llvals.push(cx.scalar_to_backend_with_pac( InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx), Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(pointer_size), }, cx.type_ptr_ext(address_space), + pac_metadata, )); next_offset = offset + pointer_size_bytes; } @@ -141,7 +167,19 @@ fn codegen_static_initializer<'ll, 'tcx>( def_id: DefId, ) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> { let alloc = cx.tcx.eval_static_initializer(def_id)?; - Ok((const_alloc_to_llvm(cx, alloc.inner(), /*static*/ true), alloc)) + let attrs = cx.tcx.codegen_fn_attrs(def_id); + let is_in_init_fini: IsInitOrFini = attrs + .link_section + .map(|link_section| { + let s = link_section.as_str(); + if s.starts_with(".init_array") || s.starts_with(".fini_array") { + IsInitOrFini::Yes + } else { + IsInitOrFini::No + } + }) + .unwrap_or(IsInitOrFini::No); + Ok((const_alloc_to_llvm(cx, alloc.inner(), IsStatic::Yes, is_in_init_fini), alloc)) } fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { @@ -164,6 +202,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( if let Some(linkage) = attrs.import_linkage { debug!("get_static: sym={} linkage={:?}", sym, linkage); + let mut should_sign = false; // Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare // an extern_weak function, otherwise a global with the desired linkage. let g1 = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) { @@ -176,8 +215,13 @@ fn check_and_apply_linkage<'ll, 'tcx>( && let ty::FnPtr(sig, header) = args.type_at(0).kind() { let fn_sig = sig.with(*header); - let fn_abi = cx.fn_abi_of_fn_ptr(fn_sig, ty::List::empty()); + // Decide if the initializer needs to be signed + if cx.sess().target.env == Env::Pauthtest + && matches!(fn_sig.abi(), ExternAbi::C { .. }) + { + should_sign = true; + } cx.declare_fn(sym, &fn_abi, None) } else { cx.declare_global(sym, cx.type_i8()) @@ -206,7 +250,24 @@ fn check_and_apply_linkage<'ll, 'tcx>( }) }); llvm::set_linkage(g2, llvm::Linkage::InternalLinkage); - llvm::set_initializer(g2, g1); + + // Sign the function pointer that is used to initialize the global + let initializer = if should_sign { + let key: u32 = 0; + let discriminator: u64 = 0; + + const_ptr_auth( + cx.const_bitcast(g1, llty), + key, + discriminator, + None, /* address_diversity */ + ) + } else { + g1 + }; + + llvm::set_initializer(g2, initializer); + g2 } else if cx.tcx.sess.target.arch == Arch::X86 && common::is_mingw_gnu_toolchain(&cx.tcx.sess.target) @@ -775,7 +836,7 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value { // FIXME: should we cache `const_alloc_to_llvm` to avoid repeating this for the // same `ConstAllocation`? - let cv = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); + let cv = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No); let gv = self.static_addr_of_impl(cv, alloc.inner().align, kind); // static_addr_of_impl returns the bare global variable, which might not be in the default diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 5b730b820b84a..9b0df5d0038b4 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -688,6 +688,24 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } } + pub(crate) fn add_ptrauth_elf_got_flag(&self) { + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "ptrauth-elf-got", + 1, + ); + } + + pub(crate) fn add_ptrauth_sign_personality_flag(&self) { + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "ptrauth-sign-personality", + 1, + ); + } + // We do our best here to match what Clang does when compiling Objective-C natively. // See Clang's `CGObjCCommonMac::EmitImageInfo`: // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5085 @@ -832,8 +850,12 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { get_fn(self, instance) } - fn get_fn_addr(&self, instance: Instance<'tcx>) -> &'ll Value { - get_fn(self, instance) + fn get_fn_addr(&self, instance: Instance<'tcx>, pac: Option) -> &'ll Value { + let llfn = get_fn(self, instance); + match pac { + Some(pac) => common::maybe_sign_fn_ptr(self, instance, llfn, pac), + None => llfn, + } } fn eh_personality(&self) -> &'ll Value { @@ -875,13 +897,16 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let tcx = self.tcx; let llfn = match tcx.lang_items().eh_personality() { - Some(def_id) if name.is_none() => self.get_fn_addr(ty::Instance::expect_resolve( - tcx, - self.typing_env(), - def_id, - ty::List::empty(), - DUMMY_SP, - )), + Some(def_id) if name.is_none() => self.get_fn_addr( + ty::Instance::expect_resolve( + tcx, + self.typing_env(), + def_id, + ty::List::empty(), + DUMMY_SP, + ), + Some(PacMetadata::default()), + ), _ => { let name = name.unwrap_or("rust_eh_personality"); if let Some(llfn) = self.get_declared_value(name) { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 0d3d682ece21f..35ee878a73049 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -25,7 +25,7 @@ use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; use rustc_target::callconv::PassMode; -use rustc_target::spec::{Arch, Os}; +use rustc_target::spec::{Arch, Env, Os}; use tracing::debug; use crate::abi::FnAbiLlvmExt; @@ -34,13 +34,14 @@ use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; use crate::builder::gpu_offload::{ OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload, }; +use crate::common::pauth_fn_attrs; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; use crate::errors::{ AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch, OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, }; -use crate::llvm::{self, Type, Value}; +use crate::llvm::{self, Attribute, AttributePlace, Type, Value}; use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; @@ -1658,6 +1659,13 @@ fn get_rust_try_fn<'a, 'll, 'tcx>( ExternAbi::Rust, )); let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen); + if cx.sess().target.env == Env::Pauthtest { + let attrs: Vec<&Attribute> = + pauth_fn_attrs().iter().map(|name| llvm::CreateAttrString(cx.llcx, name)).collect(); + let (_ty, rust_try_fn) = rust_try; + crate::attributes::apply_to_llfn(rust_try_fn, AttributePlace::Function, &attrs); + } + cx.rust_try_fn.set(Some(rust_try)); rust_try } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 525d1dbe9d0d3..6b487e5ca1347 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2584,4 +2584,11 @@ unsafe extern "C" { Aliasee: &Value, Name: *const c_char, ) -> &'ll Value; + + pub(crate) fn LLVMRustConstPtrAuth( + ptr: *mut Value, + key: u32, + disc: u64, + addr_diversity: *mut Value, + ) -> *mut Value; } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 2ec19b1795b5a..b9be706c3509b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -475,3 +475,19 @@ pub(crate) fn add_alias<'ll>( ) -> &'ll Value { unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) } } + +/// Safe wrapper for `LLVMRustConstPtrAuth`. +pub(crate) fn const_ptr_auth<'ll>( + ptr: &'ll Value, + key: u32, + disc: u64, + addr_diversity: Option<&'ll Value>, +) -> &'ll Value { + unsafe { + let addr_div_ptr = addr_diversity.map_or(std::ptr::null_mut(), |v| v as *const _ as *mut _); + + let result = LLVMRustConstPtrAuth(ptr as *const _ as *mut _, key, disc, addr_div_ptr); + + &*result + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 180559d28d848..d60763dde3537 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -391,6 +391,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { cfg.has_reliable_f128 = match (target_arch, target_os) { // Unsupported https://github.com/llvm/llvm-project/issues/121122 (Arch::AmdGpu, _) => false, + // Pauthtest musl does not support 128-bit floating point math. + (Arch::AArch64, _) if *target_env == Env::Pauthtest => false, // Unsupported (Arch::Arm64EC, _) => false, // Selection bug . This issue is closed diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 82e51dc9b0a65..119b2d072b7e5 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -492,7 +492,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( return None; } - let main_llfn = cx.get_fn_addr(instance); + let main_llfn = cx.get_fn_addr(instance, Some(PacMetadata::default())); let entry_fn = create_entry_fn::(cx, main_llfn, main_def_id, entry_type); return Some(entry_fn); @@ -552,7 +552,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx.tcx().mk_args(&[main_ret_ty.into()]), DUMMY_SP, ); - let start_fn = cx.get_fn_addr(start_instance); + let start_fn = cx.get_fn_addr(start_instance, Some(PacMetadata::default())); let i8_ty = cx.type_i8(); let arg_sigpipe = bx.const_u8(sigpipe); diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index de79acd165f0f..d95a808b0d4dc 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -117,7 +117,11 @@ pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let tcx = bx.tcx(); let def_id = tcx.require_lang_item(li, span); let instance = ty::Instance::mono(tcx, def_id); - (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance) + ( + bx.fn_abi_of_instance(instance, ty::List::empty()), + bx.get_fn_addr(instance, Some(PacMetadata::default())), + instance, + ) } pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1b96be12f71da..db0d4891ad8c5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -657,7 +657,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => ( false, - bx.get_fn_addr(drop_fn), + bx.get_fn_addr(drop_fn, Some(PacMetadata::default())), bx.fn_abi_of_instance(drop_fn, ty::List::empty()), drop_fn, ), @@ -1032,7 +1032,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) .unwrap(); - (None, Some(bx.get_fn_addr(instance))) + (None, Some(bx.get_fn_addr(instance, Some(PacMetadata::default())))) } _ => (Some(instance), None), } @@ -1338,7 +1338,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let fn_ptr = match (instance, llfn) { - (Some(instance), None) => bx.get_fn_addr(instance), + (Some(instance), None) => bx.get_fn_addr(instance, Some(PacMetadata::default())), (_, Some(llfn)) => llfn, _ => span_bug!(fn_span, "no instance or llfn for call"), }; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index f9e4a6a352bac..76549159260f9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -423,7 +423,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args, ) .unwrap(); - OperandValue::Immediate(bx.get_fn_addr(instance)) + OperandValue::Immediate(bx.get_fn_addr(instance, + Some(PacMetadata::default()), + )) } _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), } @@ -437,7 +439,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args, ty::ClosureKind::FnOnce, ); - OperandValue::Immediate(bx.cx().get_fn_addr(instance)) + OperandValue::Immediate(bx.cx().get_fn_addr(instance, + Some(PacMetadata::default()), + )) } _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), } @@ -636,7 +640,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }; - let fn_ptr = bx.get_fn_addr(instance); + let fn_ptr = bx.get_fn_addr(instance, Some(PacMetadata::default())); let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); let fn_ty = bx.fn_decl_backend_type(fn_abi); let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() { diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 22784a8868ab5..20738ba79e9fb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -2,6 +2,7 @@ use rustc_abi as abi; use rustc_middle::mir::interpret::Scalar; use super::BackendTypes; +use crate::traits::PacMetadata; pub trait ConstCodegenMethods: BackendTypes { // Constant constructors @@ -38,7 +39,16 @@ pub trait ConstCodegenMethods: BackendTypes { fn const_to_opt_uint(&self, v: Self::Value) -> Option; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value { + self.scalar_to_backend_with_pac(cv, layout, llty, None) + } + fn scalar_to_backend_with_pac( + &self, + cv: Scalar, + layout: abi::Scalar, + llty: Self::Type, + pac: Option, + ) -> Self::Value; fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 6a0f889833492..1c2c9afd38b22 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -6,6 +6,39 @@ use rustc_session::Session; use super::BackendTypes; +/// Strategy for incorporating address-based diversity into PAC computation. +pub enum AddressDiversity { + /// No address diversity is applied. + None, + /// Use the actual memory address for diversification. + Real, + /// Use a fixed synthetic value instead of the real address, + /// i.e. `1` is used for `.init_array` / `.fini_array`. + Synthetic(u64), +} + +impl Default for AddressDiversity { + fn default() -> Self { + AddressDiversity::None + } +} + +/// Metadata used for pointer authentication. +pub struct PacMetadata { + /// The PAC key to use. + pub key: u32, + /// Discriminator value used to diversify the PAC. + pub disc: u64, + /// Controls how address diversity is applied when computing the PAC. + pub addr_diversity: AddressDiversity, +} + +impl Default for PacMetadata { + fn default() -> Self { + PacMetadata { key: 0, disc: 0, addr_diversity: AddressDiversity::default() } + } +} + pub trait MiscCodegenMethods<'tcx>: BackendTypes { fn vtables( &self, @@ -18,7 +51,7 @@ pub trait MiscCodegenMethods<'tcx>: BackendTypes { ) { } fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; - fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; + fn get_fn_addr(&self, instance: Instance<'tcx>, pac: Option) -> Self::Value; fn eh_personality(&self) -> Self::Function; fn sess(&self) -> &Session; fn set_frame_pointer_type(&self, llfn: Self::Function); diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index f46d07ea5008e..ed2dad5a510cd 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -42,7 +42,7 @@ pub use self::coverageinfo::CoverageInfoBuilderMethods; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; pub use self::declare::PreDefineCodegenMethods; pub use self::intrinsic::IntrinsicCallBuilderMethods; -pub use self::misc::MiscCodegenMethods; +pub use self::misc::{AddressDiversity, MiscCodegenMethods, PacMetadata}; pub use self::statics::{StaticBuilderMethods, StaticCodegenMethods}; pub use self::type_::{ ArgAbiBuilderMethods, BaseTypeCodegenMethods, DerivedTypeCodegenMethods, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c310e580af559..ee60da44119fe 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1829,6 +1829,36 @@ extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) { return Intrinsic::isTargetIntrinsic(ID); } +extern "C" LLVMValueRef LLVMRustConstPtrAuth(LLVMValueRef Ptr, uint32_t Key, + uint64_t Disc, + LLVMValueRef AddrDiversity) { + auto *V = unwrap(Ptr); + auto *C = dyn_cast(V); + if (!C) + return Ptr; + if (!C->getType()->isPointerTy()) + return Ptr; + if (isa(C) || isa(C)) + return Ptr; + + LLVMContext &Ctx = C->getContext(); + auto *KeyC = ConstantInt::get(Type::getInt32Ty(Ctx), Key); + auto *DiscC = ConstantInt::get(Type::getInt64Ty(Ctx), Disc); + auto *PTy = cast(C->getType()); + Constant *AddrDiv = + AddrDiversity ? dyn_cast(unwrap(AddrDiversity)) + : ConstantPointerNull::get(cast(C->getType())); + assert(AddrDiv && "Failed to get Address Diversity"); + llvm::Type *PtrTy = llvm::PointerType::get(Ctx, PTy->getAddressSpace()); +#if LLVM_VERSION_GE(22, 0) + auto *DeactivationSym = llvm::Constant::getNullValue(PtrTy); + + return wrap(ConstantPtrAuth::get(C, KeyC, DiscC, AddrDiv, DeactivationSym)); +#else + return wrap(ConstantPtrAuth::get(C, KeyC, DiscC, AddrDiv)); +#endif +} + // Statically assert that the fixed metadata kind IDs declared in // `metadata_kind.rs` match the ones actually used by LLVM. #define FIXED_MD_KIND(VARIANT, VALUE) \ diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 295d9c3617778..1e07ce99a638b 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -149,6 +149,12 @@ pub(crate) struct CannotMixAndMatchSanitizers { )] pub(crate) struct CannotEnableCrtStaticLinux; +#[derive(Diagnostic)] +#[diag( + "pauthtest ABI is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`" +)] +pub(crate) struct CannotEnableCrtStaticPauthtest; + #[derive(Diagnostic)] #[diag("`-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`")] pub(crate) struct SanitizerCfiRequiresLto; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9fc6036b98b34..e6ca97fb8b6fd 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2669,6 +2669,7 @@ options! { "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"), + ptrauth_elf_got: bool = (false, parse_bool, [TRACKED], "enable signing of ELF GOT entries"), query_dep_graph: bool = (false, parse_bool, [UNTRACKED], "enable queries of the dependency graph for regression testing (default: no)"), randomize_layout: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a9e7f1503b9ca..5285799c4d3f1 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -28,7 +28,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{RealFileName, Span, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{ - Arch, CodeModel, DebuginfoKind, Os, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, + Arch, CodeModel, DebuginfoKind, Env, Os, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target, TargetTuple, TlsModel, apple, }; @@ -1200,6 +1200,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux); } + // Using static linking is prohibited on pauthtest target + if sess.crt_static(None) && sess.target.env == Env::Pauthtest { + sess.dcx().emit_err(errors::CannotEnableCrtStaticPauthtest); + } + // LLVM CFI requires LTO. if sess.is_sanitizer_cfi_enabled() && !(sess.lto() == config::Lto::Fat || sess.opts.cg.linker_plugin_lto.enabled()) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 768e43146a0c1..7a1257bfbff8a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1503,6 +1503,7 @@ supported_targets! { ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), ("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl), + ("aarch64-unknown-linux-pauthtest", aarch64_unknown_linux_pauthtest), ("aarch64_be-unknown-linux-musl", aarch64_be_unknown_linux_musl), ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), ("i686-unknown-linux-musl", i686_unknown_linux_musl), @@ -2057,6 +2058,7 @@ crate::target_spec_enum! { P1 = "p1", P2 = "p2", P3 = "p3", + Pauthtest = "pauthtest", Uclibc = "uclibc", V5 = "v5", Unspecified = "", diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_pauthtest.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_pauthtest.rs new file mode 100644 index 0000000000000..694296cbfa40b --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_pauthtest.rs @@ -0,0 +1,36 @@ +use crate::spec::{ + Arch, Env, FramePointer, LinkSelfContainedDefault, StackProbeType, Target, TargetMetadata, + TargetOptions, base, +}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "aarch64-unknown-linux-pauthtest".into(), + metadata: TargetMetadata { + description: Some("ARM64 Linux with pauth enabled musl".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 64, + data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + arch: Arch::AArch64, + + options: TargetOptions { + env: Env::Pauthtest, + // `pauthtest` requires v8.3a, which includes lse, no need for outline-atomics + features: "+v8.3a,+pauth".into(), + max_atomic_width: Some(128), + stack_probes: StackProbeType::Inline, + crt_static_default: false, + crt_static_allows_dylibs: false, + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, + link_self_contained: LinkSelfContainedDefault::False, + mcount: "\u{1}_mcount".into(), + ..base::linux::opts() + }, + } +} diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 3b951899dfec9..0b67f4f8b5e37 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -409,9 +409,15 @@ mod imp { unsafe { // this way someone on any unix-y OS can check that all these compile - if cfg!(all(target_os = "linux", not(target_env = "musl"))) { + if cfg!(all( + target_os = "linux", + not(any(target_env = "musl", target_env = "pauthtest")) + )) { install_main_guard_linux(page_size) - } else if cfg!(all(target_os = "linux", target_env = "musl")) { + } else if cfg!(all( + target_os = "linux", + any(target_env = "musl", target_env = "pauthtest") + )) { install_main_guard_linux_musl(page_size) } else if cfg!(target_os = "freebsd") { #[cfg(not(target_os = "freebsd"))] @@ -588,7 +594,10 @@ mod imp { let mut guardsize = 0; assert_eq!(libc::pthread_attr_getguardsize(attr.as_ptr(), &mut guardsize), 0); if guardsize == 0 { - if cfg!(all(target_os = "linux", target_env = "musl")) { + if cfg!(all( + target_os = "linux", + any(target_env = "musl", target_env = "pauthtest") + )) { // musl versions before 1.1.19 always reported guard // size obtained from pthread_attr_get_np as zero. // Use page size as a fallback. @@ -604,7 +613,10 @@ mod imp { let stackaddr = stackptr.addr(); ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) { Some(stackaddr - guardsize..stackaddr) - } else if cfg!(all(target_os = "linux", target_env = "musl")) { + } else if cfg!(all( + target_os = "linux", + any(target_env = "musl", target_env = "pauthtest") + )) { Some(stackaddr - guardsize..stackaddr) } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc"))) { diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index 019d5629d6d6e..ea1a6be30354d 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -89,6 +89,34 @@ const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 +unsafe fn sign_lpad(context: *mut uw::_Unwind_Context, lpad: *const u8) -> *const u8 { + cfg_select! { + all(target_env = "pauthtest", target_arch = "aarch64") => { + // DWARF register number for SP on AArch64. + const SP_REG: i32 = 31; + + unsafe { + let sp = uw::_Unwind_GetGR(context, SP_REG) as u64; + let mut addr = lpad as usize; + + // `pacib` corresponds to `ptrauth_key_process_dependent_code` in . + core::arch::asm!( + "pacib {addr}, {sp}", + addr = inout(reg) addr, + sp = in(reg) sp, + options(nostack, preserves_flags) + ); + + lpad.with_addr(addr) + } + } + _ => { + let _ = context; + lpad + } + } +} + // The following code is based on GCC's C and C++ personality routines. For reference, see: // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c @@ -239,7 +267,8 @@ cfg_select! { exception_object.cast(), ); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null()); - uw::_Unwind_SetIP(context, lpad); + let maybe_signed_lpad = sign_lpad(context, lpad); + uw::_Unwind_SetIP(context, maybe_signed_lpad); uw::_URC_INSTALL_CONTEXT } EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR, diff --git a/library/std/tests/pipe_subprocess.rs b/library/std/tests/pipe_subprocess.rs index c51a4459e718b..7b034f8129d12 100644 --- a/library/std/tests/pipe_subprocess.rs +++ b/library/std/tests/pipe_subprocess.rs @@ -12,10 +12,15 @@ fn main() { fn parent() { let me = env::current_exe().unwrap(); + // If `runner` is set up for current target, we'll be executing `./runner ./test`, not + // just `./test`. For such a case, use the same arguments for child to avoid executing + // `runner` without actual executable. + let args = env::args(); let (rx, tx) = pipe().unwrap(); assert!( process::Command::new(me) + .args(args) .env("I_AM_THE_CHILD", "1") .stdout(tx) .status() diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs index 93f73ccad3ea4..b1973b54d7670 100644 --- a/library/std/tests/process_spawning.rs +++ b/library/std/tests/process_spawning.rs @@ -26,8 +26,16 @@ fn issue_15149() { env::join_paths(paths).unwrap() }; - let child_output = - process::Command::new("mytest").env("PATH", &path).arg("child").output().unwrap(); + // If `runner` is set up for current target, we'll be executing `./runner ./test`, not + // just `./test`. For such a case, use the same arguments for child to avoid executing + // `runner` without actual executable. + let args = env::args(); + let child_output = process::Command::new("mytest") + .args(args) + .env("PATH", &path) + .arg("child") + .output() + .unwrap(); assert!( child_output.status.success(), diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs index c0bbc7d4efa88..dec33ffeedd34 100644 --- a/library/std_detect/src/detect/os/linux/auxvec.rs +++ b/library/std_detect/src/detect/os/linux/auxvec.rs @@ -51,7 +51,7 @@ pub(crate) struct AuxVec { /// Note that run-time feature detection is not invoked for features that can /// be detected at compile-time. /// -/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos}*` and +/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos,pauthtest}*` and /// `*-android*` targets rather than `dlsym` it because we can safely assume /// `getauxval` is linked to the binary. /// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) @@ -125,7 +125,7 @@ fn getauxval(key: usize) -> Result { any( all( target_os = "linux", - any(target_env = "gnu", target_env = "musl", target_env = "ohos"), + any(target_env = "gnu", target_env = "musl", target_env = "ohos", target_env = "pauthtest"), ), target_os = "android", ) => { diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index cce6ca748cccd..49727ae546960 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -94,6 +94,11 @@ cfg_select! { } } +// For pauthtest the only supported unwinding mechanism is provided by libunwind. +#[cfg(target_env = "pauthtest")] +#[link(name = "unwind")] +unsafe extern "C" {} + // This is the same as musl except that we default to using the system libunwind // instead of libgcc. #[cfg(target_env = "ohos")] diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 991592ec522d0..368587b8c584e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -10,6 +10,7 @@ use std::collections::HashSet; use std::env::split_paths; use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; +use std::process::Command; use std::{env, fs, iter}; use build_helper::exit; @@ -2227,7 +2228,13 @@ Please disable assertions with `rust.debug-assertions = false`. "-Lnative={}", builder.test_helpers_out(test_compiler.host).display() )); - targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); + let target_helpers = builder.test_helpers_out(target); + targetflags.push(format!("-Lnative={}", target_helpers.display())); + if target.is_pauthtest() { + // For the pauthtest target, embed an rpath to the directory containing the helper + // dynamic library. + targetflags.push(format!("-Clink-arg=-Wl,-rpath,{}", target_helpers.display())); + } } for flag in hostflags { @@ -3858,32 +3865,54 @@ impl Step for TestHelpers { }; let dst = builder.test_helpers_out(target); let src = builder.src.join("tests/auxiliary/rust_test_helpers.c"); - if up_to_date(&src, &dst.join("librust_test_helpers.a")) { - return; - } - let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target); t!(fs::create_dir_all(&dst)); - let mut cfg = cc::Build::new(); - // We may have found various cross-compilers a little differently due to our - // extra configuration, so inform cc of these compilers. Note, though, that - // on MSVC we still need cc's detection of env vars (ugh). - if !target.is_msvc() { - if let Some(ar) = builder.ar(target) { - cfg.archiver(ar); + if !up_to_date(&src, &dst.join("librust_test_helpers.a")) { + let mut cfg = cc::Build::new(); + + // We may have found various cross-compilers a little differently due to our + // extra configuration, so inform cc of these compilers. Note, though, that + // on MSVC we still need cc's detection of env vars (ugh). + if !target.is_msvc() { + if let Some(ar) = builder.ar(target) { + cfg.archiver(ar); + } + cfg.compiler(builder.cc(target)); + } + cfg.cargo_metadata(false) + .out_dir(&dst) + .target(&target.triple) + .host(&builder.config.host_target.triple) + .opt_level(0) + .warnings(false) + .debug(false) + .file(builder.src.join("tests/auxiliary/rust_test_helpers.c")) + .compile("rust_test_helpers"); + } + if target.is_pauthtest() { + let so = dst.join("librust_test_helpers.so"); + if up_to_date(&src, &so) { + return; + } + + let status = Command::new(builder.cc(target)) + .arg("-target") + .arg(target.triple) + .arg("-march=armv8.3-a+pauth") + .arg("-fPIC") + .arg("-shared") + .arg("-O0") // Use O0 to match what static library is compiled at. + .arg("-o") + .arg(&so) + .arg(&src) + .status() + .expect("Failed to run pauthtest clang for librust_test_helpers.so"); + + if !status.success() { + panic!("Linking of pauthtest librust_test_helpers.so failed"); } - cfg.compiler(builder.cc(target)); } - cfg.cargo_metadata(false) - .out_dir(&dst) - .target(&target.triple) - .host(&builder.config.host_target.triple) - .opt_level(0) - .warnings(false) - .debug(false) - .file(builder.src.join("tests/auxiliary/rust_test_helpers.c")) - .compile("rust_test_helpers"); } } diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs index 8457607b897dd..5f87e81e2ccb7 100644 --- a/src/bootstrap/src/core/config/target_selection.rs +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -78,6 +78,10 @@ impl TargetSelection { self.contains("msvc") } + pub fn is_pauthtest(&self) -> bool { + self.triple == "aarch64-unknown-linux-pauthtest" + } + pub fn is_windows(&self) -> bool { self.contains("windows") } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index c4a6b68aedee8..fce98ffb0db21 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -21,7 +21,7 @@ use crate::builder::Kind; use crate::core::build_steps::tool; use crate::core::config::{CompilerBuiltins, Target}; use crate::utils::exec::command; -use crate::{Build, Subcommand}; +use crate::{Build, Subcommand, t}; pub struct Finder { cache: HashMap>, @@ -39,6 +39,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "x86_64-unknown-linux-gnumsan", "x86_64-unknown-linux-gnutsan", + "aarch64-unknown-linux-pauthtest", // Stage 0 compiler is not guaranteed to see pauthtest yet. ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM @@ -413,6 +414,53 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake { cmd_finder.must_have("wasm-component-ld"); } + + // aarch64-unknown-linux-pauthtest must use clang + if !skip_tools_checks && target.is_pauthtest() { + let cc_tool = build.cc_tool(*target); + let linker_path = build + .linker(*target) + .unwrap_or_else(|| panic!("{} requires an explicit clang linker", target.triple)); + + if !cc_tool.is_like_clang() { + panic!( + "Clang is required to build C code for {} target, got:\n\ + cc tool: `{}`,\n\ + linker: `{}`\n", + target.triple, + cc_tool.path().display(), + linker_path.display(), + ); + } + let cc_canon = t!(fs::canonicalize(cc_tool.path())); + let linker_canon = t!(fs::canonicalize(&linker_path)); + if cc_canon != linker_canon { + panic!( + "CC and Linker are expected to be the same for {} target, got:\n\ + CC: `{}`,\n\ + Linker: `{}`\n", + target.triple, + cc_canon.display(), + linker_canon.display(), + ); + } + + let output = + command(cc_tool.path()).arg("-dumpversion").run_capture_stdout(&build).stdout(); + let version_str = output.trim(); + let mut parts = version_str.split('.').map(|s| s.parse::().unwrap_or(0)); + let major = parts.next().unwrap_or(0); + let minor = parts.next().unwrap_or(0); + let patch = parts.next().unwrap_or(0); + if (major, minor, patch) < (22, 1, 0) { + panic!( + "clang version too old: {} ({} target trequires >= 22.1.0), path: {}", + target.triple, + version_str, + cc_tool.path().display() + ); + } + } } if let Some(ref s) = build.config.ccache { diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index cc10f476780c5..591ab929fdf67 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -49,6 +49,7 @@ - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [aarch64-unknown-linux-gnu](platform-support/aarch64-unknown-linux-gnu.md) - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md) + - [aarch64-unknown-linux-pauthtest](platform-support/aarch64-unknown-linux-pauthtest.md) - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md) - [aarch64v8r-unknown-none*](platform-support/aarch64v8r-unknown-none.md) - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 26dd6b31b8991..a8825ccd12ba3 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -266,6 +266,7 @@ target | std | host | notes [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit [`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) +[`aarch64-unknown-linux-pauthtest`](platform-support/aarch64-unknown-linux-pauthtest.md) | ✓ | ✓ | ARM64 PAC ELF ABI [`aarch64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | ARM64 Managarm [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md new file mode 100644 index 0000000000000..6c96c758c2553 --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md @@ -0,0 +1,422 @@ +# aarch64-unknown-linux-pauthtest + +**Tier: 3** + +The target enables Pointer Authentication Code (PAC) support in Rust on AArch64 +ELF based Linux systems using a pauthtest ABI (provided by LLVM) and +pauthtest-enabled sysroot with custom musl, serving as a reference libc +implementation. + +Supported features include: +* authenticating signed function pointers for extern "C" function calls + (corresponds to `-fptrauth-calls` included in pauthtest ABI as defined in + LLVM) +* signing return address before spilling to stack and authenticating return + address after restoring from stack for non-leaf functions (corresponds to + `-fptrauth-returns`) +* trapping if authentication failure is detected and FPAC feature is not present + (corresponds to `-fptrauth-auth-traps`) +* signing of init/fini array entries with the signing schema used for pauthtest + ABI (corresponding to `-fptrauth-init-fini`, + `-fptrauth-init-fini-address-discrimination`) +* non-ABI-affecting indirect control flow hardening features included in + pauthtest ABI (corresponding to `-faarch64-jump-table-hardening`, + `-fptrauth-indirect-gotos`) +* signed ELF GOT entries (gated behind `-Z ptrauth-elf-got`, off by default) + +A tracking issue for adding support for the AArch64 pointer authentication ABI +in Rust can be found at +[#148640](https://github.com/rust-lang/rust/issues/148640). + +Existing compiler support, such as enabling branch authentication instructions +(i.e.: `-Z branch-protection`) provide limited functionality, mainly signing +return addresses (`pac-ret`). The new target goes further by enabling ABI-level +pointer authentication support. + +## Target maintainers + +[@jchlanda](https://github.com/jchlanda) + +## Requirements + +This target supports cross-compilation from any Linux host, but execution +requires AArch64 with pointer authentication support (ARMv8.3-A or higher). + +## Standard library support + +Full std support is available: `core`, `alloc`, and `std` all build +successfully. All library tests (`core`, `alloc`, `std`) pass for this target as +well. + +## Building the toolchain + +Building this target requires a pauthtest-enabled sysroot based on a custom musl +toolchain. The sysroot must be available on the system before compilation. To +build it, follow the instructions in the [build scripts +repo](https://github.com/access-softek/pauth-toolchain-build-scripts). + +The target uses Clang, please make sure it is v22.1.0 or higher. When using a +system-provided Clang, a compiler wrapper is required to supply the necessary +flags. Please consult the listing: + +```sh +#!/usr/bin/env sh + +clang \ + -target aarch64-unknown-linux-pauthtest \ + -march=armv8.3-a+pauth \ + --sysroot /aarch64-linux-pauthtest/usr \ + -resource-dir /lib/clang/ \ + --rtlib=compiler-rt \ + --ld-path=/usr/bin/ld.lld \ + --unwindlib=libunwind \ + "$@" +``` + +The Rust compiler validates the name of the configured C compiler, so when using +a wrapper its name must contain `clang`. A recommended name is +`aarch64-unknown-linux-pauthtest-clang`. Update the script to set `--sysroot` +and `-resource-dir` correctly by replacing `` with the directory +produced by the build scripts and the `` with LLVM's version. Make the +wrapper executable. + +To verify that the toolchain layout is correct, check that: +* the sysroot contains a pauthtest-enabled version of libunwind + (`/aarch64-linux-pauthtest/usr/lib/libunwind.so`), +* the Clang resource directory contains the appropriate `compiler-rt` objects + (`/lib/clang//lib/aarch64-unknown-linux-pauthtest/{clang_rt.crtbegin.o,clang_rt.crtend.o}`) + +When using the AccessSoftek scripts to build the sysroot, the result includes a +Clang-based toolchain. In this case, no wrapper script is required, +`/bin/aarch64-linux-pauthtest-clang` can be used directly. + +## Building the target + +Introduction of `aarch64-unknown-linux-pauthtest` target needs to be propagated +to various crates/repos, so that they can correctly recognise and handle it. +Specifically: +* `cc-rs`: https://github.com/jchlanda/cc-rs/tree/jakub/cc-v1.2.28-pauthtest +* `libc`: https://github.com/jchlanda/libc/tree/jakub/0.2.183-pauthtest +* `backtrace`: https://github.com/jchlanda/backtrace-rs/tree/jakub/backtrace-v0.3.76-pauthtest + +The patched versions of `cc-rs` and `libc` will have to be registered through +`[patch.crates-io]` section of `Cargo.toml` files both in: +`/src/bootstrap/` and `/library/`. Check out `cc-rs` and +`libc` to `/patches` and update config files. See attached diff for +details: + +
+ +```diff +diff --git a/library/Cargo.toml b/library/Cargo.toml +index e30e6240942..fb5a12f0065 100644 +--- a/library/Cargo.toml ++++ b/library/Cargo.toml +@@ -59,3 +59,4 @@ rustflags = ["-Cpanic=abort"] + rustc-std-workspace-core = { path = 'rustc-std-workspace-core' } + rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' } + rustc-std-workspace-std = { path = 'rustc-std-workspace-std' } ++libc = { path = '/patches/libc' } +diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml +index e1725db60cf..46763cdf9a4 100644 +--- a/src/bootstrap/Cargo.toml ++++ b/src/bootstrap/Cargo.toml +@@ -94,3 +94,6 @@ debug = 0 + [profile.dev.package] + # Only use debuginfo=1 to further reduce compile times. + bootstrap.debug = 1 ++ ++[patch.crates-io] ++cc = { path = '/patches/cc-rs' } +``` + +
+ +In contrast to `cc-rs` and `libc`, which are external crates resolved from +[crates.io](https://crates.io/) and can be overridden using `[patch.crates-io]`, +`backtrace` is included in the Rust repository as a git submodule under +`/library/backtrace`. At the time of writing, the necessary change +has not yet been committed there, which means an in-tree patch is currently +required. The patch: + +
+ +```diff +diff --git a/src/backtrace/libunwind.rs b/src/backtrace/libunwind.rs +index 0564f2e..a8a0d1a 100644 +--- a/src/backtrace/libunwind.rs ++++ b/src/backtrace/libunwind.rs +@@ -79,6 +79,18 @@ impl Frame { + // clause, and if this is fixed that test in theory can be run on macOS! + if cfg!(target_vendor = "apple") { + self.ip() ++ } else if cfg!(target_env = "pauthtest") { ++ // NOTE: As ip here is not signed (raw, non-PAC-enabled pointer) we ++ // must not use uw::_Unwind_FindEnclosingFunction. This is because, ++ // for pauthtest toolchain, libunwind will try to authenticate and ++ // resign it. Signing here (apart from risking creating a signing ++ // oracle) is not possible. According to the schema the value must ++ // be signed using SP as the discriminator - which is the problem. ++ // SP obtained here would not match the SP at the auth-resign time, ++ // as uw::_Unwind_FindEnclosingFunction creates a new context so ++ // the SP used for signing here would belong to a different frame ++ // that the one used for auth-resign. Hence return a raw value. ++ self.ip() + } else { + unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) } + } +``` + +
+ +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["aarch64-unknown-linux-pauthtest"] +``` + +Specify the binaries used by the target. + +```toml +[target.aarch64-unknown-linux-pauthtest] +cc = "/aarch64-unknown-linux-pauthtest-clang" +ar = "/llvm-ar" +ranlib = "/llvm-ranlib" +linker = "/aarch64-unknown-linux-pauthtest-clang" +runner = "/aarch64-linux-pauthtest/usr/lib/libc.so" +``` + +Note that `cc` and `linker` must refer to the same binary (either Clang itself +or its wrapper). The bootstrap process will fail if they differ. On AArch64 +systems `runner` should point to the dynamic loader provided by the toolchain. +On non-AArch64 systems it should point to `qemu-aarch64` with `QEMU_LD_PREFIX` +configured appropriately. + +## Building Rust programs + +Rust does not currently ship precompiled artifacts for this target. Programs +must be built using a locally compiled Rust toolchain, with +`aarch64-unknown-linux-pauthtest` target enabled. + +For a comprehensive example of how to interact between C and Rust programs +within the testing framework please consult +`/tests/run-make/pauth-quicksort-c-driver/rmake.rs`, the test builds +a C executable linked against Rust library. +`/tests/run-make/pauth-quicksort-rust-driver/rmake.rs` shows how to +link a Rust program against a library compiled from a C source file. + +### Minimal standalone Rust and C interoperability example + +A minimal standalone example demonstrating Rust and C interoperability on the +`aarch64-unknown-linux-pauthtest` target is listed below. + +The example shows: +* compilation of a small C shared library (`plugin.c`) exposing two functions: + `add` and `sub` +* linking it dynamically into a Rust binary + +At runtime, Rust: +* randomly selects one function (`add` or `sub`) +* calls it indirectly via a function pointer + +It ensures the call is performed via a pointer-authenticated indirect call. + +
+ +* Project structure + +```text +Cargo.toml +build.rs +src/main.rs +c_src/plugin.c +``` + +* `Cargo.toml` + +```markdown +[package] +name = "rust_c_indirect" +version = "0.1.0" +edition = "2021" +build = "build.rs" + +[dependencies] +rand = "0.8" + +[patch.crates-io] +# Please notice, that libc needs to be patched. +libc = { path = '/patches/libc' } +``` + +* `build.rs` + +```rust,no_run +use std::env; +use std::path::Path; +use std::process::Command; + +fn main() { + println!("cargo:rerun-if-changed=c_src/plugin.c"); + + let clang = "/aarch64-unknown-linux-pauthtest-clang"; + + let out_dir = env::var("OUT_DIR").unwrap(); + let lib_path = Path::new(&out_dir).join("libplugin.so"); + let c_src = "c_src/plugin.c"; + + let status = Command::new(clang) + .args(["-shared", "-fPIC", c_src]) + .arg("-o") + .arg(&lib_path) + .status() + .unwrap_or_else(|_| panic!("failed to build shared library")); + assert!(status.success(), "failed to build shared library"); + + println!("cargo:rustc-link-search=native={}", out_dir); + println!("cargo:rustc-link-lib=dylib=plugin"); +} +``` + +* `src/main.rs` + +```rust,ignore (avoid complains about unresolved rand) +use std::os::raw::c_int; + +extern "C" { + fn add(a: c_int, b: c_int) -> c_int; + fn sub(a: c_int, b: c_int) -> c_int; +} + +type Op = unsafe extern "C" fn(c_int, c_int) -> c_int; + +fn main() { + unsafe { + let mut rng = rand::thread_rng(); + let coin = rng.gen_bool(0.5); + + let op: Op = if coin { + println!("rand result: true -> using add: 40 + 2"); + add + } else { + println!("rand result: false -> using sub: 40 - 2"); + sub + }; + + let result = op(40, 2); + + println!("result = {}", result); + } +} +``` + +* `c_src/plugin.c` + +```c +#include + +int add(int a, int b) { + return a + b; +} + +int sub(int a, int b) { + return a - b; +} +``` + +
+ +The program can be compiled with: `cargo build --target +aarch64-unknown-linux-pauthtest --release`. And then run with: +`/aarch64-linux-pauthtest/usr/lib/libc.so +./target/aarch64-unknown-linux-pauthtest/release/rust_c_indirect`. Please make +sure that `LD_LIBRARY_PATH` points to both pauthtest sysroot lib directory and +the directory containing `libplugin.so`. For example: +`LD_LIBRARY_PATH=/aarch64-linux-pauthtest/usr/lib/:./target/aarch64-unknown-linux-pauthtest/release/build/rust_c_indirect-/out/`. + +To inspect pointer authentication behavior in IR, build with: +`RUSTFLAGS="--emit=llvm-ir"`. This generates an LLVM IR file, e.g.: +`target/aarch64-unknown-linux-pauthtest/release/deps/rust_c_indirect-*.ll`. +Relevant excerpt: + +```llvm +%op.sroa.0.0 = phi ptr [ ptrauth (ptr @sub, i32 0), %bb5 ], + [ ptrauth (ptr @add, i32 0), %bb3 ] + +%8 = tail call noundef i32 %op.sroa.0.0(i32 noundef 40, i32 noundef 2) + [ "ptrauth"(i32 0, i64 0) ] +``` + +Which shows that: +* function pointers (`add` / `sub`) are signed using `ptrauth` +* the call is performed indirectly via a signed pointer +* the `ptrauth` operand bundle enforces authentication at call time + +## Cross-compilation + +This target can be cross-compiled from any Linux-based host, but execution +requires an AArch64 system that implements Pointer Authentication (PAC). In +practice, this means a CPU conforming to at least the Armv8.3-A architecture, +where the +[FEAT_PAuth](https://developer.arm.com/documentation/109697/2025_06/Feature-descriptions/The-Armv8-3-architecture-extension?lang=en#md448-the-armv83-architecture-extension__feat_FEAT_PAuth) +extension is defined. + +Cross-compilation has been successfully performed on both +`aarch64-unknown-linux-gnu` and `x86_64-unknown-linux-gnu` hosts. + +## Testing + +This target can be tested as normal with `x.py`. +The following categories are supported (all present in tree): +* Assembly tests + * targets-aarch64_unknown_linux_pauthtest.rs +* LLVM IR/codegen tests + * pauth-extern-c.rs + * pauth-extern-c-direct-indirect-call.rs + * pauth-init-fini.rs + * pauth-attr-special-funcs.rs +* End-to-end execution tests + * Rust-driven quicksort (pauth-quicksort-rust-driver) + * C-driven quicksort (pauth-quicksort-c-driver) +* UI error reporting (pauthtest does not support `+crt-static`) + * crt-static-pauthtest.rs + +All tests from `codegen-llvm`, `library`, `run-make` and `ui` subsets are +expected to pass. + +Command to run all passing tests: + +```sh +x.py test --target aarch64-unknown-linux-pauthtest --force-rerun \ + codegen-llvm library run-make ui \ + tests/assembly-llvm/targets/targets-aarch64_unknown_linux_pauthtest.rs \ + tests/codegen-llvm/pauth-attr-special-funcs.rs \ + tests/codegen-llvm/pauth-extern-c.rs \ + tests/codegen-llvm/pauth-extern-c-direct-indirect-call.rs \ + tests/codegen-llvm/pauth-extern-weak-global.rs \ + tests/codegen-llvm/pauth-init-fini.rs \ + tests/run-make/pauth-quicksort-rust-driver \ + tests/run-make/pauth-quicksort-c-driver \ + tests/ui/statics/crt-static-pauthtest.rs +``` + +## Cross-compilation toolchains and C code + +This target supports interoperability with C code. Use the PAC-enabled LLVM +sysroot, described in building the sysroot section of this document. C code must +be compiled with the pauthtest aware compiler. Mixed Rust/C programs are +supported and tested (e.g. quicksort examples). Pointer authentication semantics +must be consistent across Rust and C components. The target only supports +dynamic linking with the custom interpreter. + +## Limitation +Operand bundles should only be attached to indirect function calls. However, +function pointer signing is currently performed in `get_fn_addr`, which causes +the logic to be applied too broadly, including to function values (not just +pointers). As a result, direct calls using signed function values must also +receive operand bundles. Once this is resolved, we should analyze each call and +skip direct calls. + +For more information please see the discussion in the [rust-lang issue +tracker](https://github.com/rust-lang/rust/issues/152532). diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index d3422a93075b8..0936a36efc81c 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -605,6 +605,7 @@ fn human_readable_target_env(env: Symbol) -> Option<&'static str> { P1 => "WASIp1", P2 => "WASIp2", P3 => "WASIp3", + Pauthtest => "pauthtest", Relibc => "relibc", Sgx => "SGX", Sim => "Simulator", diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 5421a97201737..4e20b818ba2b8 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -49,6 +49,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-aarch64", "ignore-aarch64-pc-windows-msvc", "ignore-aarch64-unknown-linux-gnu", + "ignore-aarch64-unknown-linux-pauthtest", "ignore-aix", "ignore-android", "ignore-apple", @@ -210,6 +211,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-aarch64", "only-aarch64-apple-darwin", "only-aarch64-unknown-linux-gnu", + "only-aarch64-unknown-linux-pauthtest", "only-aarch64-unknown-uefi", "only-apple", "only-arm", diff --git a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs index 1177c1e68ed56..690db72b1322b 100644 --- a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs +++ b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs @@ -2,6 +2,9 @@ //@ compile-flags: -Copt-level=3 //@ only-aarch64 //@ only-linux +// aarch64-unknown-linux-pauthtest requires armv8.3-a, which includes Large System Extensions, +// providing hardware implementations of atomic operations. +//@ ignore-aarch64-unknown-linux-pauthtest #![crate_type = "rlib"] diff --git a/tests/assembly-llvm/targets/targets-aarch64_unknown_linux_pauthtest.rs b/tests/assembly-llvm/targets/targets-aarch64_unknown_linux_pauthtest.rs new file mode 100644 index 0000000000000..edf0823f54da2 --- /dev/null +++ b/tests/assembly-llvm/targets/targets-aarch64_unknown_linux_pauthtest.rs @@ -0,0 +1,40 @@ +//@ assembly-output: emit-asm +//@ only-aarch64-unknown-linux-pauthtest +//@ revisions: aarch64_unknown_linux_pauthtest +//@ [aarch64_unknown_linux_pauthtest] compile-flags: --target=aarch64-unknown-linux-pauthtest +//@ [aarch64_unknown_linux_pauthtest] needs-llvm-components: aarch64 + +#![no_std] +#![crate_type = "lib"] + +#[no_mangle] +#[inline(never)] +pub extern "C" fn add(a: i32, b: i32) -> i32 { + a + b +} + +#[no_mangle] +#[inline(never)] +fn call_through(f: extern "C" fn(i32, i32) -> i32, x: i32) -> i32 { + f(x, 1) +} + +#[no_mangle] +#[inline(never)] +pub fn call_add(x: i32) -> i32 { + call_through(add, x) +} + +// CHECK-LABEL: call_through: +// CHECK: mov [[PTR:x[0-9]+]], x0 +// CHECK: mov w0, w1 +// CHECK: mov w1, #1 +// CHECK: braaz [[PTR]] + +// CHECK-LABEL: call_add: +// CHECK: adrp [[GOT_REG:x[0-9]+]], :got:add +// CHECK: ldr [[GOT_REG]], [[[GOT_REG]], :got_lo12:add] +// CHECK: paciza [[FN_REG:x[0-9]+]] +// CHECK: mov w1, w0 +// CHECK: mov x0, [[FN_REG]] +// CHECK: b call_through diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index ce6629b4f27ce..6364e34069f09 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -55,6 +55,9 @@ //@ revisions: aarch64_unknown_linux_ohos //@ [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos //@ [aarch64_unknown_linux_ohos] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_linux_pauthtest +//@ [aarch64_unknown_linux_pauthtest] compile-flags: --target aarch64-unknown-linux-pauthtest +//@ [aarch64_unknown_linux_pauthtest] needs-llvm-components: aarch64 //@ revisions: aarch64_unknown_managarm_mlibc //@ [aarch64_unknown_managarm_mlibc] compile-flags: --target aarch64-unknown-managarm-mlibc //@ [aarch64_unknown_managarm_mlibc] needs-llvm-components: aarch64 diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 24da2c4a1c4e8..5a0f8c1483d0f 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -280,6 +280,14 @@ impl Sync for () {} impl Sync for [T; N] {} +// Function pointers are treated as `Sync` to match real `core` behavior. +// +// We intentionally only cover the zero-argument form since tests using this minicore +// are simplified to `fn() -> R` / `extern "C" fn() -> R` to avoid arity-specific +// complexity. See: tests/codegen-llvm/pauth-extern-weak-global.rs for the use case. +impl Sync for fn() -> R {} +impl Sync for unsafe extern "C" fn() -> R {} + #[lang = "drop_in_place"] fn drop_in_place(_: *mut T) {} diff --git a/tests/codegen-llvm/box-uninit-bytes.rs b/tests/codegen-llvm/box-uninit-bytes.rs index 7ac929646cd4d..fc47e42d6f9db 100644 --- a/tests/codegen-llvm/box-uninit-bytes.rs +++ b/tests/codegen-llvm/box-uninit-bytes.rs @@ -43,4 +43,4 @@ pub fn box_lotsa_padding() -> Box { // from the CHECK-NOT above, and also verify the attributes got set reasonably. // CHECK: declare {{(dso_local )?}}noalias noundef ptr @{{.*}}__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef range(i{{[0-9]+}} 1, {{-2147483647|-9223372036854775807}})) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] -// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} } +// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned"){{.*}} allocsize(0) {{(uwtable )?}}{{.*}}"alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs index 5df256961de57..5ea25c0f4ea81 100644 --- a/tests/codegen-llvm/cffi/c-variadic.rs +++ b/tests/codegen-llvm/cffi/c-variadic.rs @@ -1,5 +1,9 @@ //@ needs-unwind //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +// Pauthtest generates pointer authentication metadata for call instructions +// and wraps function pointers in ConstPtrAuth. Disable this test for this target +// to avoid clutter from pointer authentication complexity. +//@ ignore-aarch64-unknown-linux-pauthtest #![crate_type = "lib"] #![feature(c_variadic)] diff --git a/tests/codegen-llvm/inline-always-works-always.rs b/tests/codegen-llvm/inline-always-works-always.rs index 07200fd9e373a..91a13ab1a7da3 100644 --- a/tests/codegen-llvm/inline-always-works-always.rs +++ b/tests/codegen-llvm/inline-always-works-always.rs @@ -2,6 +2,8 @@ //@[NO-OPT] compile-flags: -Copt-level=0 //@[SIZE-OPT] compile-flags: -Copt-level=s //@[SPEED-OPT] compile-flags: -Copt-level=3 +// Pointer authenticated calls are not guaranteed to be inlined. +//@ ignore-aarch64-unknown-linux-pauthtest #![crate_type = "rlib"] diff --git a/tests/codegen-llvm/issues/issue-73258.rs b/tests/codegen-llvm/issues/issue-73258.rs index c9eceb0dccf73..ff4c1aa8a0603 100644 --- a/tests/codegen-llvm/issues/issue-73258.rs +++ b/tests/codegen-llvm/issues/issue-73258.rs @@ -3,6 +3,8 @@ #![crate_type = "lib"] // Adapted from +// We explicitly match against `call{{.*}}(` because the aarch64-unknown-linux-pauthtest target +// emits `ptrauth-calls` attribute, which would otherwise make a plain `call` match ambiguous. #[derive(Clone, Copy)] #[repr(u8)] @@ -17,7 +19,7 @@ pub enum Foo { #[no_mangle] pub unsafe fn issue_73258(ptr: *const Foo) -> Foo { // CHECK-NOT: icmp - // CHECK-NOT: call + // CHECK-NOT: call{{.*}}( // CHECK-NOT: br {{.*}} // CHECK-NOT: select @@ -25,14 +27,14 @@ pub unsafe fn issue_73258(ptr: *const Foo) -> Foo { // CHECK-SAME: !range ! // CHECK-NOT: icmp - // CHECK-NOT: call + // CHECK-NOT: call{{.*}}( // CHECK-NOT: br {{.*}} // CHECK-NOT: select // CHECK: ret i8 %[[R]] // CHECK-NOT: icmp - // CHECK-NOT: call + // CHECK-NOT: call{{.*}}( // CHECK-NOT: br {{.*}} // CHECK-NOT: select let k: Option = Some(ptr.read()); diff --git a/tests/codegen-llvm/pauth-attr-special-funcs.rs b/tests/codegen-llvm/pauth-attr-special-funcs.rs new file mode 100644 index 0000000000000..0d3d164c51444 --- /dev/null +++ b/tests/codegen-llvm/pauth-attr-special-funcs.rs @@ -0,0 +1,31 @@ +//@ only-aarch64-unknown-linux-pauthtest +//@ compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 +// Make sure that compiler generated functions (main wrapper and __rust_try) also have ptrauth +// attributes set correctly. Rustc only generates __rust_try at O0, so use that opt level for the +// test. + +//@ needs-llvm-components: aarch64 + +use std::panic; + +// CHECK: define {{.*}} @__rust_try{{.*}} [[ATTR_TRY:#[0-9]+]] +// CHECK: define {{.*}} @main{{.*}} [[ATTR_MAIN:#[0-9]+]] + +// CHECK: attributes [[ATTR_TRY]] = { {{.*}}"aarch64-jump-table-hardening" +// CHECK-DAG: "ptrauth-auth-traps" +// CHECK-DAG: "ptrauth-calls" +// CHECK-DAG: "ptrauth-indirect-gotos" +// CHECK-DAG: "ptrauth-returns" + +// CHECK: attributes [[ATTR_MAIN]] = { {{.*}}"aarch64-jump-table-hardening" +// CHECK-DAG: "ptrauth-auth-traps" +// CHECK-DAG: "ptrauth-calls" +// CHECK-DAG: "ptrauth-indirect-gotos" +// CHECK-DAG: "ptrauth-returns" +fn main() { + let _ = panic::catch_unwind(|| { + panic!("BOOM"); + }); +} + +// CHECK: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} diff --git a/tests/codegen-llvm/pauth-extern-c-direct-indirect-call.rs b/tests/codegen-llvm/pauth-extern-c-direct-indirect-call.rs new file mode 100644 index 0000000000000..39e1e685deee2 --- /dev/null +++ b/tests/codegen-llvm/pauth-extern-c-direct-indirect-call.rs @@ -0,0 +1,87 @@ +// ignore-tidy-linelength +//@ only-aarch64-unknown-linux-pauthtest +//@ revisions: O0_PAUTH O3_PAUTH + +//@ [O0_PAUTH] needs-llvm-components: aarch64 +//@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 +//@ [O3_PAUTH] needs-llvm-components: aarch64 +//@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 + +// Make sure that direct extern "C" calls are not handled by pointer authentication operand bundle +// logic. +use std::ffi::c_void; +use std::hint::black_box; + +extern "C" { + fn rand() -> i32; + fn add(a: i32, b: i32) -> i32; + fn sub(a: i32, b: i32) -> i32; + + // Corresponds to: void *woof; + static mut woof: *mut c_void; + fn direct_function_taking_void_arg(data: *mut c_void); + fn direct_no_arg(); + fn direct_function_taking_fp_arg(func: unsafe extern "C" fn()); +} + +type CFnPtr = unsafe extern "C" fn(i32, i32) -> i32; + +// CHECK-LABE: test_indirect_call +#[inline(never)] +fn test_indirect_call() { + let fp_add: CFnPtr = black_box(add); + let fp_sub: CFnPtr = black_box(sub); + + unsafe { + // O0_PAUTH: call {{.*}}i32 %fp_add({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: call {{.*}}i32 %fp_add({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + let _id1 = fp_add(7, 4); + // O0_PAUTH: call {{.*}}i32 %fp_sub({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: call {{.*}}i32 %fp_sub({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + let _id2 = fp_sub(10, 6); + } + + // Also test calling via conditional pointer + unsafe { + // O0_PAUTH: call {{.*}}i32 ptrauth (ptr @rand, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: call {{.*}}i32 @rand() # + let use_add = rand() % 2 == 0; + // O0_PAUTH: store ptr ptrauth (ptr @sub, i32 0), ptr %[[FP_O0:[a-zA-Z0-9_.]+]] + // O0_PAUTH: store ptr ptrauth (ptr @add, i32 0), ptr %[[FP_O0]]{{.*}} + // O0_PAUTH: %[[LOAD_FP_O0:[a-zA-Z0-9_.]+]] = load ptr, ptr %[[FP_O0]]{{.*}} + // O3_PAUTH: %[[FP_O3:.*]] = select i1 %{{.*}}, ptr ptrauth (ptr @add, i32 0), ptr ptrauth (ptr @sub, i32 0) + let fp: CFnPtr = if use_add { add } else { sub }; + // O0_PAUTH: call i32 %[[LOAD_FP_O0]](i32 1, i32 2) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: call {{.*}}i32 %[[FP_O3]](i32 noundef 1, i32 noundef 2) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + let _id3 = fp(1, 2); + } + + unsafe { + direct_function_taking_fp_arg(direct_no_arg); + } +} + +// CHECK-LABE: test_direct_call +#[inline(never)] +fn test_direct_call() { + unsafe { + // O0_PAUTH: call {{.*}}i32 ptrauth (ptr @add, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: call {{.*}}i32 @add(i32 {{.*}}2, i32 {{.*}}3) # + let _d1 = add(2, 3); + // O0_PAUTH: call {{.*}}i32 ptrauth (ptr @sub, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: call {{.*}}i32 @sub(i32 {{.*}}5, i32 {{.*}}1) # + let _d2 = sub(5, 1); + + // O0_PAUTH: call {{.*}}void ptrauth (ptr @direct_function_taking_void_arg, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: {{(tail )?}}call void @direct_function_taking_void_arg(ptr noundef %{{.*}}) # + direct_function_taking_void_arg(woof); + } +} + +fn main() { + test_indirect_call(); + test_direct_call(); +} + +// O0_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} +// O3_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} diff --git a/tests/codegen-llvm/pauth-extern-c.rs b/tests/codegen-llvm/pauth-extern-c.rs new file mode 100644 index 0000000000000..2c5612cff4be4 --- /dev/null +++ b/tests/codegen-llvm/pauth-extern-c.rs @@ -0,0 +1,75 @@ +// ignore-tidy-linelength +//@ only-aarch64-unknown-linux-pauthtest +//@ add-minicore + +//@ revisions: O0_PAUTH O3_PAUTH O0_PAUTH-ELF-GOT O3_PAUTH-ELF-GOT O0_NO_PAUTH O3_NO_PAUTH + +//@ [O0_PAUTH] needs-llvm-components: aarch64 +//@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 +//@ [O3_PAUTH] needs-llvm-components: aarch64 +//@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 +//@ [O0_PAUTH-ELF-GOT] needs-llvm-components: aarch64 +//@ [O0_PAUTH-ELF-GOT] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 -Z ptrauth-elf-got +//@ [O3_PAUTH-ELF-GOT] needs-llvm-components: aarch64 +//@ [O3_PAUTH-ELF-GOT] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 -Z ptrauth-elf-got +//@ [O0_NO_PAUTH] needs-llvm-components: aarch64 +//@ [O0_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=0 +//@ [O3_NO_PAUTH] needs-llvm-components: aarch64 +//@ [O3_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=3 + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core)] + +extern crate minicore; + +type FnPtr = unsafe extern "C" fn(i32, i32) -> i32; +// O0_NO_PAUTH-NOT: "ptrauth"(i32 +// O3_NO_PAUTH-NOT: "ptrauth"(i32 + +// O0_PAUTH: define {{.*}}test_entry +// O3_PAUTH: define {{.*}}test_entry +#[no_mangle] +pub unsafe extern "C" fn test_entry(x: usize) { + // O0_PAUTH: call{{.*}}_RNvCshUtaFcP1mZ5_14pauth_extern_c7call_it(ptr ptrauth (ptr @external_c_callee, i32 0), i32 5, i32 7) + // O3_PAUTH: call{{.*}}_RNvCshUtaFcP1mZ5_14pauth_extern_c7call_it(ptr{{.*}}ptrauth (ptr @external_c_callee, i32 0), i32{{.*}}5, i32{{.*}}7) + let _ = call_it(external_c_callee, 5, 7); +} + +// O0_PAUTH: define {{.*}}pauth_extern_c7call_it{{.*}} #[[ATTR_O0_1:[0-9]+]] +// O3_PAUTH: define {{.*}}pauth_extern_c7call_it{{.*}} #[[ATTR_O3_1:[0-9]+]] +#[inline(never)] +pub fn call_it(fn_ptr: FnPtr, arg_1: i32, arg_2: i32) -> i32 { + // O0_PAUTH: call i32 %fn_ptr(i32 %arg_1, i32 %arg_2){{.*}}[ "ptrauth"(i32 0, i64 0) ] + // O3_PAUTH: call{{.*}}i32 %fn_ptr(i32{{.*}}%arg_1, i32{{.*}}%arg_2){{.*}}[ "ptrauth"(i32 0, i64 0) ] + unsafe { fn_ptr(arg_1, arg_2) } +} + +extern "C" { + fn external_c_callee(a: i32, b: i32) -> i32; +} + +// O0_PAUTH-CHECK: attributes #[[ATTR_O0_1]] = { {{.*}}"aarch64-jump-table-hardening" +// O0_PAUTH-CHECK-SAME: "ptrauth-auth-traps" +// O0_PAUTH-CHECK-SAME: "ptrauth-calls" +// O0_PAUTH-CHECK-SAME: "ptrauth-indirect-gotos" +// O0_PAUTH-CHECK-SAME: "ptrauth-returns" + +// O3_PAUTH-CHECK: attributes #[[ATTR_O3_1]] = { {{.*}}"aarch64-jump-table-hardening" +// O3_PAUTH-CHECK-SAME: "ptrauth-auth-traps" +// O3_PAUTH-CHECK-SAME: "ptrauth-calls" +// O3_PAUTH-CHECK-SAME: "ptrauth-indirect-gotos" +// O3_PAUTH-CHECK-SAME: "ptrauth-returns" + +// O0_PAUTH-ELF-GOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} +// O0_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} +// O0_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} +// O3_PAUTH-ELF-GOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} +// O3_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} +// O3_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} + +// O0_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} +// O0_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} +// O3_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} +// O3_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} diff --git a/tests/codegen-llvm/pauth-extern-weak-global.rs b/tests/codegen-llvm/pauth-extern-weak-global.rs new file mode 100644 index 0000000000000..d39bfb0118a4b --- /dev/null +++ b/tests/codegen-llvm/pauth-extern-weak-global.rs @@ -0,0 +1,38 @@ +// ignore-tidy-linelength +//@ only-aarch64-unknown-linux-pauthtest +//@ revisions: O0_PAUTH O3_PAUTH O0_NO_PAUTH O3_NO_PAUTH +//@ add-minicore + +//@ [O0_PAUTH] needs-llvm-components: aarch64 +//@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 +//@ [O3_PAUTH] needs-llvm-components: aarch64 +//@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 +//@ [O0_NO_PAUTH] needs-llvm-components: aarch64 +//@ [O0_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=0 +//@ [O3_NO_PAUTH] needs-llvm-components: aarch64 +//@ [O3_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=3 + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core)] +#![feature(linkage)] + +extern crate minicore; +use minicore::*; + +// O0_PAUTH: @{{[0-9A-Za-z_]+}}FUNCTION_PTR_DECL = constant ptr ptrauth (ptr @extern_weak_fn, i32 0) +// O0_PAUTH: declare i64 @extern_weak_fn({{.*}}) +// O3_PAUTH: @{{[0-9A-Za-z_]+}}FUNCTION_PTR_DECL = constant ptr ptrauth (ptr @extern_weak_fn, i32 0) +// O3_PAUTH: declare {{.*}} i64 @extern_weak_fn({{.*}}) +// +// O0_NO_PAUTH-NOT: ptr ptrauth +// O3_NO_PAUTH-NOT: ptr ptrauth +extern "C" { + #[link_name = "extern_weak_fn"] + #[linkage = "extern_weak"] + fn extern_weak_fn() -> i64; +} + +#[used] +static FUNCTION_PTR_DECL: unsafe extern "C" fn() -> i64 = extern_weak_fn; diff --git a/tests/codegen-llvm/pauth-init-fini.rs b/tests/codegen-llvm/pauth-init-fini.rs new file mode 100644 index 0000000000000..1485edfb6e1d2 --- /dev/null +++ b/tests/codegen-llvm/pauth-init-fini.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//@ only-aarch64-unknown-linux-pauthtest +//@ revisions: O0_PAUTH O3_PAUTH + +//@ [O0_PAUTH] needs-llvm-components: aarch64 +//@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 +//@ [O3_PAUTH] needs-llvm-components: aarch64 +//@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 + +// Make sure that init/fini metadata uses correct discriminator: 0xd9d4/55764 + +#![crate_type = "lib"] +#![feature(linkage)] + +// O0_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" +// O3_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" +#[used] +#[link_section = ".init_array.90"] +static GLOBAL_INIT: extern "C" fn() = init_fn; + +// O0_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" +// O3_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" +#[used] +#[link_section = ".fini_array.90"] +static GLOBAL_FINI: extern "C" fn(i32) = fini_fn; + +extern "C" fn init_fn() {} +extern "C" fn fini_fn(_: i32) {} diff --git a/tests/incremental/auxiliary/issue-54059.rs b/tests/incremental/auxiliary/issue-54059.rs index 6bbc94149e822..9c535ce0c7b90 100644 --- a/tests/incremental/auxiliary/issue-54059.rs +++ b/tests/incremental/auxiliary/issue-54059.rs @@ -40,7 +40,8 @@ proc_macro_expr_impl! { } } -#[link(name="rust_test_helpers")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers"))] extern "C" { pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; } diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs index 96b8ade1f1b16..f68567faa4260 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs @@ -6,6 +6,8 @@ //@ needs-target-std //@ ignore-android: FIXME(#142855) //@ ignore-sgx: (x86 machine code cannot be directly executed) +//@ ignore-aarch64-unknown-linux-pauthtest: (pauthtest requires non-trivial compilation of c +//sources, ignore the test for now). use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; diff --git a/tests/run-make/pauth-quicksort-c-driver/main.c b/tests/run-make/pauth-quicksort-c-driver/main.c new file mode 100644 index 0000000000000..58f8d149cc446 --- /dev/null +++ b/tests/run-make/pauth-quicksort-c-driver/main.c @@ -0,0 +1,45 @@ +#include +#include + +#define NUM_ELEMS 5 + +void quickSort(void *Base, size_t N, size_t Size, + int (*Cmp)(const void *, const void *)); + +#ifdef __cplusplus +} +#endif + +int cmpI32Ascending(const void *LHS, const void *RHS) { + int32_t x = *(const int32_t *)LHS; + int32_t y = *(const int32_t *)RHS; + + if (x < y) + return -1; + else if (x > y) + return 1; + else + return 0; +} + +int main() { + int32_t Data[NUM_ELEMS] = {4, 2, 5, 3, 1}; + + printf("Before sorting: "); + for (int i = 0; i < NUM_ELEMS; i++) + printf("%d ", Data[i]); + printf("\n"); + + quickSort(Data, NUM_ELEMS, sizeof(int32_t), cmpI32Ascending); + + printf("After sorting: "); + for (int i = 0; i < NUM_ELEMS; i++) + printf("%d ", Data[i]); + printf("\n"); + + for (size_t i = 1; i < NUM_ELEMS; i++) + if (Data[i - 1] > Data[i]) + return 42; + + return 0; +} diff --git a/tests/run-make/pauth-quicksort-c-driver/quicksort.rs b/tests/run-make/pauth-quicksort-c-driver/quicksort.rs new file mode 100644 index 0000000000000..ac73dced2e1fc --- /dev/null +++ b/tests/run-make/pauth-quicksort-c-driver/quicksort.rs @@ -0,0 +1,66 @@ +use std::mem::size_of; +use std::os::raw::{c_int, c_void}; +use std::ptr; + +unsafe fn swap_i32(lhs: *mut i32, rhs: *mut i32) { + ptr::swap(lhs, rhs); +} + +unsafe fn partition( + arr: *mut i32, + low: isize, + high: isize, + cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, +) -> isize { + let pivot = arr.offset(low); + let mut i = low; + let mut j = high; + + while i < j { + while i <= high - 1 && cmp(arr.offset(i) as *const c_void, pivot as *const c_void) <= 0 { + i += 1; + } + + while j >= low + 1 && cmp(arr.offset(j) as *const c_void, pivot as *const c_void) > 0 { + j -= 1; + } + + if i < j { + swap_i32(arr.offset(i), arr.offset(j)); + } + } + + swap_i32(arr.offset(low), arr.offset(j)); + j +} + +unsafe fn quicksort_rec( + arr: *mut i32, + low: isize, + high: isize, + cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, +) { + if low < high { + let part = partition(arr, low, high, cmp); + quicksort_rec(arr, low, part - 1, cmp); + quicksort_rec(arr, part + 1, high, cmp); + } +} + +#[no_mangle] +pub extern "C" fn quickSort( + base: *mut c_void, + n: usize, + size: usize, + cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, +) { + if size != size_of::() { + std::process::abort(); + } + + if n > 1 { + unsafe { + quicksort_rec(base as *mut i32, 0, (n as isize) - 1, cmp); + } + } +} diff --git a/tests/run-make/pauth-quicksort-c-driver/rmake.rs b/tests/run-make/pauth-quicksort-c-driver/rmake.rs new file mode 100644 index 0000000000000..539dc7a3bdcd4 --- /dev/null +++ b/tests/run-make/pauth-quicksort-c-driver/rmake.rs @@ -0,0 +1,43 @@ +// Test compilation flow using custom pauth-enabled toolchain and signing extern "C" function +// pointers used from within rust. Note that in order for the test to work the location of the +// toolchain's sysroot has to be provided via env variable (`PAUTHTEST_SYSROOT`). The test assumes +// that pauthtest-enabled `clang` is available on the path. +// In this test rust is the driver - providing the data and the comparison function; while c - +// provides the implementation of quicksort algorithm and is the user of the data and comparator. + +//@ only-aarch64-unknown-linux-pauthtest + +use run_make_support::{cc, env_var, rfs, run, run_fail, rustc}; + +fn main() { + // Use CC and CC_DEFAULT_FLAGS env variables to set up linker for rustc. This results in the + // same command as cc(). The CC env variable corresponds to cc field in the config toml file. + // This field is required to point to a clang family compiler on aarch64-unknown-linux-pauthtest + // target. + let rust_lib_name = "rust_quicksort"; + rustc() + .target("aarch64-unknown-linux-pauthtest") + .crate_type("cdylib") + .input("quicksort.rs") + .linker(&env_var("CC")) + .link_args(&env_var("CC_DEFAULT_FLAGS")) + .crate_name(rust_lib_name) + .run(); + + let exe_name = "main"; + cc().out_exe(exe_name) + .input("main.c") + .args(&[ + "-march=armv8.3-a+pauth", + "-target", + "aarch64-unknown-linux-pauthtest", + &format!("-l{}", rust_lib_name), + ]) + .library_search_path(".") + .run(); + + run(exe_name); + + rfs::remove_file(format!("{}{rust_lib_name}.{}", "lib", "so")); + run_fail(exe_name); +} diff --git a/tests/run-make/pauth-quicksort-rust-driver/main.rs b/tests/run-make/pauth-quicksort-rust-driver/main.rs new file mode 100644 index 0000000000000..37700e0ddc169 --- /dev/null +++ b/tests/run-make/pauth-quicksort-rust-driver/main.rs @@ -0,0 +1,43 @@ +use std::os::raw::{c_int, c_void}; + +#[link(name = "quicksort")] +extern "C" { + fn quickSort( + base: *mut c_void, + n: usize, + size: usize, + cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, + ); +} + +extern "C" fn cmp_i32_ascending(a: *const c_void, b: *const c_void) -> c_int { + unsafe { + let x = *(a as *const i32); + let y = *(b as *const i32); + + if x < y { + -1 + } else if x > y { + 1 + } else { + 0 + } + } +} + +fn main() { + let mut data: [i32; 5] = [4, 2, 5, 3, 1]; + println!("Before sorting: {:?}", data); + + unsafe { + quickSort( + data.as_mut_ptr() as *mut c_void, + data.len(), + std::mem::size_of::(), + cmp_i32_ascending, + ); + } + + println!("After sorting: {:?}", data); + assert!(data.windows(2).all(|w| w[0] <= w[1])); +} diff --git a/tests/run-make/pauth-quicksort-rust-driver/quicksort.c b/tests/run-make/pauth-quicksort-rust-driver/quicksort.c new file mode 100644 index 0000000000000..029435d562bb6 --- /dev/null +++ b/tests/run-make/pauth-quicksort-rust-driver/quicksort.c @@ -0,0 +1,50 @@ +#include +#include +#include + +void swap(void *A, void *B, size_t Size) { + unsigned char Tmp[Size]; + memcpy(Tmp, A, Size); + memcpy(A, B, Size); + memcpy(B, Tmp, Size); +} + +int partition(void *Base, int Low, int High, size_t Size, + int (*Cmp)(const void *, const void *)) { + char *Arr = (char *)Base; + + void *Pivot = Arr + Low * Size; + int i = Low; + int j = High; + + while (i < j) { + while (i <= High - 1 && Cmp(Arr + i * Size, Pivot) <= 0) + i++; + + while (j >= Low + 1 && Cmp(Arr + j * Size, Pivot) > 0) + j--; + + if (i < j) + swap(Arr + i * Size, Arr + j * Size, Size); + } + + swap(Arr + Low * Size, Arr + j * Size, Size); + return j; +} + +void quickSortRec(void *Base, int Low, int High, size_t Size, + int (*Cmp)(const void *, const void *)) { + if (Low < High) { + int Part = partition(Base, Low, High, Size, Cmp); + quickSortRec(Base, Low, Part - 1, Size, Cmp); + quickSortRec(Base, Part + 1, High, Size, Cmp); + } +} + +void quickSort(void *Base, size_t N, size_t Size, + int (*Cmp)(const void *, const void *)) { + if (Size != sizeof(int32_t)) + abort(); + if (N > 1) + quickSortRec(Base, 0, (int)N - 1, Size, Cmp); +} diff --git a/tests/run-make/pauth-quicksort-rust-driver/rmake.rs b/tests/run-make/pauth-quicksort-rust-driver/rmake.rs new file mode 100644 index 0000000000000..3f3ead7d3ead6 --- /dev/null +++ b/tests/run-make/pauth-quicksort-rust-driver/rmake.rs @@ -0,0 +1,34 @@ +// Test compilation flow using custom pauth-enabled toolchain and signing extern "C" function +// pointers used from within rust. The test assumes that pauthtest-enabled `clang` is available on +// the path. +// In this test rust is the driver - providing the data and the comparison function; while c - +// provides the implementation of quicksort algorithm and is the user of the data and comparator. + +//@ only-aarch64-unknown-linux-pauthtest + +use run_make_support::{cc, env_var, rfs, run, run_fail, rustc}; + +fn main() { + let input = "quicksort"; + let input_name = format!("{input}.c"); + let lib_name = format!("{}{input}.{}", "lib", "so"); + cc().out_exe(&lib_name) + .input(&input_name) + .args(&["-target", "aarch64-unknown-linux-pauthtest", "-march=armv8.3-a+pauth", "-shared"]) + .run(); + + // Use CC and CC_DEFAULT_FLAGS env variables to set up linker for rustc. This results in the + // same command as cc(). The CC env variable corresponds to cc field in the config toml file. + // This field is required to point to a clang family compiler on aarch64-unknown-linux-pauthtest + // target. + rustc() + .target("aarch64-unknown-linux-pauthtest") + .input("main.rs") + .linker(&env_var("CC")) + .link_args(&env_var("CC_DEFAULT_FLAGS")) + .run(); + run("main"); + + rfs::remove_file(&lib_name); + run_fail("main"); +} diff --git a/tests/run-make/rustdoc-test-builder/rmake.rs b/tests/run-make/rustdoc-test-builder/rmake.rs index 17d40c68fd922..5520426e16fa8 100644 --- a/tests/run-make/rustdoc-test-builder/rmake.rs +++ b/tests/run-make/rustdoc-test-builder/rmake.rs @@ -27,6 +27,7 @@ fn main() { // so only exercise the success path when the target can run on the host. if target().contains("wasm") || target().contains("sgx") + || target().contains("pauthtest") || std::env::var_os("REMOTE_TEST_CLIENT").is_some() { return; diff --git a/tests/ui/abi/abi-sysv64-arg-passing.rs b/tests/ui/abi/abi-sysv64-arg-passing.rs index 362a1862f9d4c..7424cfaa7202b 100644 --- a/tests/ui/abi/abi-sysv64-arg-passing.rs +++ b/tests/ui/abi/abi-sysv64-arg-passing.rs @@ -106,7 +106,8 @@ mod tests { Some(u64), } - #[link(name = "rust_test_helpers", kind = "static")] + #[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] + #[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "sysv64" { pub fn rust_int8_to_int32(_: i8) -> i32; pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; diff --git a/tests/ui/abi/anon-extern-mod.rs b/tests/ui/abi/anon-extern-mod.rs index 134542b9cff38..2c7f6a5621b27 100644 --- a/tests/ui/abi/anon-extern-mod.rs +++ b/tests/ui/abi/anon-extern-mod.rs @@ -1,6 +1,7 @@ //@ run-pass -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn rust_get_test_int() -> isize; } diff --git a/tests/ui/abi/c-stack-as-value.rs b/tests/ui/abi/c-stack-as-value.rs index 10933bdb2781f..02d5df9b8e6ac 100644 --- a/tests/ui/abi/c-stack-as-value.rs +++ b/tests/ui/abi/c-stack-as-value.rs @@ -1,7 +1,8 @@ //@ run-pass mod rustrt { - #[link(name = "rust_test_helpers", kind = "static")] + #[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] + #[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_get_test_int() -> isize; } diff --git a/tests/ui/abi/cabi-int-widening.rs b/tests/ui/abi/cabi-int-widening.rs index e211b98983731..ab57bc2f64065 100644 --- a/tests/ui/abi/cabi-int-widening.rs +++ b/tests/ui/abi/cabi-int-widening.rs @@ -1,6 +1,7 @@ //@ run-pass -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn rust_int8_to_int32(_: i8) -> i32; } diff --git a/tests/ui/abi/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs b/tests/ui/abi/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs index 559c40546a8a5..b8326e34e2f43 100644 --- a/tests/ui/abi/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs +++ b/tests/ui/abi/cross-crate/auxiliary/anon-extern-mod-cross-crate-1.rs @@ -1,6 +1,7 @@ #![crate_name = "anonexternmod"] -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_get_test_int() -> isize; } diff --git a/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs b/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs index 6b21877109664..9c073291f397d 100644 --- a/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs +++ b/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs @@ -1,7 +1,8 @@ #![crate_name = "externcallback"] #![crate_type = "lib"] -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_call( cb: extern "C" fn(u64) -> u64, diff --git a/tests/ui/abi/extern/extern-call-deep.rs b/tests/ui/abi/extern/extern-call-deep.rs index 40457ae57207d..bcfedbe37e61b 100644 --- a/tests/ui/abi/extern/extern-call-deep.rs +++ b/tests/ui/abi/extern/extern-call-deep.rs @@ -1,7 +1,8 @@ //@ run-pass //@ ignore-emscripten blows the JS stack -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_call( cb: extern "C" fn(u64) -> u64, diff --git a/tests/ui/abi/extern/extern-call-deep2.rs b/tests/ui/abi/extern/extern-call-deep2.rs index 91ca28d80c80f..e4c9a3bebafcd 100644 --- a/tests/ui/abi/extern/extern-call-deep2.rs +++ b/tests/ui/abi/extern/extern-call-deep2.rs @@ -3,7 +3,8 @@ use std::thread; -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_call( cb: extern "C" fn(u64) -> u64, diff --git a/tests/ui/abi/extern/extern-call-indirect.rs b/tests/ui/abi/extern/extern-call-indirect.rs index ef1e8ae5e760d..504e6a6af5ce0 100644 --- a/tests/ui/abi/extern/extern-call-indirect.rs +++ b/tests/ui/abi/extern/extern-call-indirect.rs @@ -1,6 +1,7 @@ //@ run-pass -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_call( cb: extern "C" fn(u64) -> u64, diff --git a/tests/ui/abi/extern/extern-call-scrub.rs b/tests/ui/abi/extern/extern-call-scrub.rs index 7df3a8f04ef1f..9fbda16467239 100644 --- a/tests/ui/abi/extern/extern-call-scrub.rs +++ b/tests/ui/abi/extern/extern-call-scrub.rs @@ -6,7 +6,8 @@ use std::thread; -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_call( cb: extern "C" fn(u64) -> u64, diff --git a/tests/ui/abi/extern/extern-pass-FiveU16s.rs b/tests/ui/abi/extern/extern-pass-FiveU16s.rs index 5f1307beb28e6..60f32c4b1500d 100644 --- a/tests/ui/abi/extern/extern-pass-FiveU16s.rs +++ b/tests/ui/abi/extern/extern-pass-FiveU16s.rs @@ -16,7 +16,8 @@ pub struct FiveU16s { five: u16, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_FiveU16s(v: FiveU16s) -> FiveU16s; } diff --git a/tests/ui/abi/extern/extern-pass-TwoU16s.rs b/tests/ui/abi/extern/extern-pass-TwoU16s.rs index 8bde553050a40..6f907f5fa1d15 100644 --- a/tests/ui/abi/extern/extern-pass-TwoU16s.rs +++ b/tests/ui/abi/extern/extern-pass-TwoU16s.rs @@ -10,7 +10,8 @@ pub struct TwoU16s { two: u16, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s; } diff --git a/tests/ui/abi/extern/extern-pass-TwoU32s.rs b/tests/ui/abi/extern/extern-pass-TwoU32s.rs index fc90eb6945c7e..c4a6438741528 100644 --- a/tests/ui/abi/extern/extern-pass-TwoU32s.rs +++ b/tests/ui/abi/extern/extern-pass-TwoU32s.rs @@ -10,7 +10,8 @@ pub struct TwoU32s { two: u32, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s; } diff --git a/tests/ui/abi/extern/extern-pass-TwoU64s.rs b/tests/ui/abi/extern/extern-pass-TwoU64s.rs index 603de2e49ab2d..dd077c930196f 100644 --- a/tests/ui/abi/extern/extern-pass-TwoU64s.rs +++ b/tests/ui/abi/extern/extern-pass-TwoU64s.rs @@ -10,7 +10,8 @@ pub struct TwoU64s { two: u64, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; } diff --git a/tests/ui/abi/extern/extern-pass-TwoU8s.rs b/tests/ui/abi/extern/extern-pass-TwoU8s.rs index a712d79a98dd2..49fc0f6bb6a66 100644 --- a/tests/ui/abi/extern/extern-pass-TwoU8s.rs +++ b/tests/ui/abi/extern/extern-pass-TwoU8s.rs @@ -10,7 +10,8 @@ pub struct TwoU8s { two: u8, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s; } diff --git a/tests/ui/abi/extern/extern-pass-char.rs b/tests/ui/abi/extern/extern-pass-char.rs index 24196c54b50d8..200c308994786 100644 --- a/tests/ui/abi/extern/extern-pass-char.rs +++ b/tests/ui/abi/extern/extern-pass-char.rs @@ -2,7 +2,8 @@ // Test a function that takes/returns a u8. -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; } diff --git a/tests/ui/abi/extern/extern-pass-double.rs b/tests/ui/abi/extern/extern-pass-double.rs index e883ebe9815ee..cf3de204d5b9a 100644 --- a/tests/ui/abi/extern/extern-pass-double.rs +++ b/tests/ui/abi/extern/extern-pass-double.rs @@ -1,6 +1,7 @@ //@ run-pass -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_double(v: f64) -> f64; } diff --git a/tests/ui/abi/extern/extern-pass-empty.rs b/tests/ui/abi/extern/extern-pass-empty.rs index 1ad52b128ad93..5c445a6384cc3 100644 --- a/tests/ui/abi/extern/extern-pass-empty.rs +++ b/tests/ui/abi/extern/extern-pass-empty.rs @@ -25,7 +25,8 @@ struct ManyInts { #[repr(C)] struct Empty; -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts); } diff --git a/tests/ui/abi/extern/extern-pass-u32.rs b/tests/ui/abi/extern/extern-pass-u32.rs index 0daff4e9f42c4..69adcbcfa92c7 100644 --- a/tests/ui/abi/extern/extern-pass-u32.rs +++ b/tests/ui/abi/extern/extern-pass-u32.rs @@ -2,7 +2,8 @@ // Test a function that takes/returns a u32. -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; } diff --git a/tests/ui/abi/extern/extern-pass-u64.rs b/tests/ui/abi/extern/extern-pass-u64.rs index f1cd6bf59c2ec..4df57f41af0da 100644 --- a/tests/ui/abi/extern/extern-pass-u64.rs +++ b/tests/ui/abi/extern/extern-pass-u64.rs @@ -2,7 +2,8 @@ // Test a call to a function that takes/returns a u64. -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; } diff --git a/tests/ui/abi/extern/extern-return-FiveU16s.rs b/tests/ui/abi/extern/extern-return-FiveU16s.rs index d8ae8b2661c5a..1175585b66bd5 100644 --- a/tests/ui/abi/extern/extern-return-FiveU16s.rs +++ b/tests/ui/abi/extern/extern-return-FiveU16s.rs @@ -9,7 +9,8 @@ pub struct FiveU16s { five: u16, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_return_FiveU16s() -> FiveU16s; } diff --git a/tests/ui/abi/extern/extern-return-TwoU16s.rs b/tests/ui/abi/extern/extern-return-TwoU16s.rs index bf909a8db24c7..8355f51e68ac9 100644 --- a/tests/ui/abi/extern/extern-return-TwoU16s.rs +++ b/tests/ui/abi/extern/extern-return-TwoU16s.rs @@ -6,7 +6,8 @@ pub struct TwoU16s { two: u16, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s; } diff --git a/tests/ui/abi/extern/extern-return-TwoU32s.rs b/tests/ui/abi/extern/extern-return-TwoU32s.rs index c528da8cfc464..ee59dfb2f61ae 100644 --- a/tests/ui/abi/extern/extern-return-TwoU32s.rs +++ b/tests/ui/abi/extern/extern-return-TwoU32s.rs @@ -6,7 +6,8 @@ pub struct TwoU32s { two: u32, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s; } diff --git a/tests/ui/abi/extern/extern-return-TwoU64s.rs b/tests/ui/abi/extern/extern-return-TwoU64s.rs index d4f9540ec7b35..70f7b8b854024 100644 --- a/tests/ui/abi/extern/extern-return-TwoU64s.rs +++ b/tests/ui/abi/extern/extern-return-TwoU64s.rs @@ -6,7 +6,8 @@ pub struct TwoU64s { two: u64, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s; } diff --git a/tests/ui/abi/extern/extern-return-TwoU8s.rs b/tests/ui/abi/extern/extern-return-TwoU8s.rs index 228b27396249b..c436ec18833d1 100644 --- a/tests/ui/abi/extern/extern-return-TwoU8s.rs +++ b/tests/ui/abi/extern/extern-return-TwoU8s.rs @@ -6,7 +6,8 @@ pub struct TwoU8s { two: u8, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s; } diff --git a/tests/ui/abi/foreign/auxiliary/foreign_lib.rs b/tests/ui/abi/foreign/auxiliary/foreign_lib.rs index 74a95b96e9fc4..06e9f58a74a78 100644 --- a/tests/ui/abi/foreign/auxiliary/foreign_lib.rs +++ b/tests/ui/abi/foreign/auxiliary/foreign_lib.rs @@ -1,7 +1,8 @@ #![crate_name = "foreign_lib"] pub mod rustrt { - #[link(name = "rust_test_helpers", kind = "static")] + #[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] + #[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_get_test_int() -> isize; } diff --git a/tests/ui/abi/foreign/foreign-fn-with-byval.rs b/tests/ui/abi/foreign/foreign-fn-with-byval.rs index 9908ec2d2c01a..79c15136a6b63 100644 --- a/tests/ui/abi/foreign/foreign-fn-with-byval.rs +++ b/tests/ui/abi/foreign/foreign-fn-with-byval.rs @@ -8,7 +8,8 @@ pub struct S { z: u64, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn get_x(x: S) -> u64; pub fn get_y(x: S) -> u64; diff --git a/tests/ui/abi/issue-28676.rs b/tests/ui/abi/issue-28676.rs index 2abb4ce52b3b3..2f3cf97fe8a35 100644 --- a/tests/ui/abi/issue-28676.rs +++ b/tests/ui/abi/issue-28676.rs @@ -15,7 +15,8 @@ pub struct Quad { mod rustrt { use super::Quad; - #[link(name = "rust_test_helpers", kind = "static")] + #[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] + #[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn get_c_many_params( _: *const (), diff --git a/tests/ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs b/tests/ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs index 314db42280d99..7b3dd2e8b376c 100644 --- a/tests/ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs +++ b/tests/ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs @@ -13,7 +13,8 @@ pub struct QuadFloats { mod rustrt { use super::QuadFloats; - #[link(name = "rust_test_helpers", kind = "static")] + #[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] + #[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn get_c_exhaust_sysv64_ints( _: *const (), diff --git a/tests/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs b/tests/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs index f694205174889..afc521106df9d 100644 --- a/tests/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs +++ b/tests/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs @@ -2,7 +2,8 @@ #![allow(dead_code)] #![allow(improper_ctypes)] -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn issue_97463_leak_uninit_data(a: u32, b: u32, c: u32) -> u16; } diff --git a/tests/ui/abi/mir/mir_codegen_calls_variadic.rs b/tests/ui/abi/mir/mir_codegen_calls_variadic.rs index 0c1a59b38d3eb..04fa9b49cd06e 100644 --- a/tests/ui/abi/mir/mir_codegen_calls_variadic.rs +++ b/tests/ui/abi/mir/mir_codegen_calls_variadic.rs @@ -1,6 +1,7 @@ //@ run-pass -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn rust_interesting_average(_: i64, ...) -> f64; } diff --git a/tests/ui/abi/numbers-arithmetic/i128-ffi.rs b/tests/ui/abi/numbers-arithmetic/i128-ffi.rs index 26d65e8bbf853..dc9f56abb1ae9 100644 --- a/tests/ui/abi/numbers-arithmetic/i128-ffi.rs +++ b/tests/ui/abi/numbers-arithmetic/i128-ffi.rs @@ -8,7 +8,8 @@ //@ ignore-windows //@ ignore-32bit -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn identity(f: u128) -> u128; fn square(f: i128) -> i128; diff --git a/tests/ui/abi/segfault-no-out-of-stack.rs b/tests/ui/abi/segfault-no-out-of-stack.rs index b122079d36f76..bc2e59b346346 100644 --- a/tests/ui/abi/segfault-no-out-of-stack.rs +++ b/tests/ui/abi/segfault-no-out-of-stack.rs @@ -10,7 +10,8 @@ use std::env; use std::ffi::c_char; use std::process::{Command, ExitStatus}; -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn rust_get_null_ptr() -> *mut c_char; } diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs index 4d0301411e0fd..b03aee1b9ed2f 100644 --- a/tests/ui/abi/stack-probes.rs +++ b/tests/ui/abi/stack-probes.rs @@ -17,7 +17,8 @@ use std::mem::MaybeUninit; use std::process::Command; use std::thread; -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { #[link_name = "rust_dbg_extern_identity_u64"] fn black_box(u: u64); diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs index 40cd57637e6cd..01eba2739190d 100644 --- a/tests/ui/abi/statics/static-mut-foreign.rs +++ b/tests/ui/abi/statics/static-mut-foreign.rs @@ -8,7 +8,8 @@ use std::ffi::c_int; -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { static mut rust_dbg_static_mut: c_int; pub fn rust_dbg_static_mut_check_four(); diff --git a/tests/ui/abi/struct-enums/struct-return.rs b/tests/ui/abi/struct-enums/struct-return.rs index 5fe80d5f670b2..0ba0a59d5dab0 100644 --- a/tests/ui/abi/struct-enums/struct-return.rs +++ b/tests/ui/abi/struct-enums/struct-return.rs @@ -39,7 +39,8 @@ pub struct CharCharFloat { mod rustrt { use super::{CharCharDouble, CharCharFloat, Floats, Quad}; - #[link(name = "rust_test_helpers", kind = "static")] + #[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] + #[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_abi_1(q: Quad) -> Quad; pub fn rust_dbg_abi_2(f: Floats) -> Floats; diff --git a/tests/ui/abi/union/union-c-interop.rs b/tests/ui/abi/union/union-c-interop.rs index 05eac446a9182..e4376ea889360 100644 --- a/tests/ui/abi/union/union-c-interop.rs +++ b/tests/ui/abi/union/union-c-interop.rs @@ -16,7 +16,8 @@ union LARGE_INTEGER { QuadPart: u64, } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER; } diff --git a/tests/ui/abi/variadic-ffi.rs b/tests/ui/abi/variadic-ffi.rs index 3ffa0bea0ecf8..71963662d225a 100644 --- a/tests/ui/abi/variadic-ffi.rs +++ b/tests/ui/abi/variadic-ffi.rs @@ -5,7 +5,8 @@ use std::ffi::VaList; -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { fn rust_interesting_average(_: u64, ...) -> f64; diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index dd1b696b76cb2..0f1896a5699e0 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `macabi`, `mlibc`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `p3`, `relibc`, `sgx`, `sim`, `uclibc`, and `v5` + = note: expected values for `target_env` are: ``, `gnu`, `macabi`, `mlibc`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `p3`, `pauthtest`, `relibc`, `sgx`, `sim`, `uclibc`, and `v5` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/float/target-has-reliable-nightly-float.rs b/tests/ui/float/target-has-reliable-nightly-float.rs index 399f101f49ae2..cef050a8c7037 100644 --- a/tests/ui/float/target-has-reliable-nightly-float.rs +++ b/tests/ui/float/target-has-reliable-nightly-float.rs @@ -21,7 +21,7 @@ pub fn has_f128_math() {} fn main() { if cfg!(target_arch = "aarch64") && cfg!(target_os = "linux") && - cfg!(not(target_env = "musl")) { + cfg!(not(any(target_env = "musl", target_env = "pauthtest"))) { // Aarch64+GNU+Linux is one target that has support for all features, so use it to spot // check that the compiler does indeed enable these gates. diff --git a/tests/ui/link-native-libs/lib-defaults.rs b/tests/ui/link-native-libs/lib-defaults.rs index 4e38adb643dbf..8d7e11b9d7299 100644 --- a/tests/ui/link-native-libs/lib-defaults.rs +++ b/tests/ui/link-native-libs/lib-defaults.rs @@ -5,7 +5,8 @@ //@ run-pass //@ compile-flags: -lrust_test_helpers -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_u32(x: u32) -> u32; } diff --git a/tests/ui/linking/auxiliary/aux-25185-1.rs b/tests/ui/linking/auxiliary/aux-25185-1.rs index 032d7d5de348b..eed03e569d336 100644 --- a/tests/ui/linking/auxiliary/aux-25185-1.rs +++ b/tests/ui/linking/auxiliary/aux-25185-1.rs @@ -2,7 +2,8 @@ #![crate_type = "rlib"] -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { pub fn rust_dbg_extern_identity_u32(u: u32) -> u32; } diff --git a/tests/ui/macros/macros-in-extern.rs b/tests/ui/macros/macros-in-extern.rs index 97780650d1126..a9a36bbcf7a8d 100644 --- a/tests/ui/macros/macros-in-extern.rs +++ b/tests/ui/macros/macros-in-extern.rs @@ -41,7 +41,8 @@ fn main() { assert_eq!(unsafe { f2() }, 2); } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { returns_isize!(rust_get_test_int); takes_u32_returns_u32!(rust_dbg_extern_identity_u32); diff --git a/tests/ui/proc-macro/macros-in-extern.rs b/tests/ui/proc-macro/macros-in-extern.rs index f39322d126e04..2d96339c2528e 100644 --- a/tests/ui/proc-macro/macros-in-extern.rs +++ b/tests/ui/proc-macro/macros-in-extern.rs @@ -9,7 +9,8 @@ fn main() { assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); } -#[link(name = "rust_test_helpers", kind = "static")] +#[cfg_attr(target_env = "pauthtest", link(name = "rust_test_helpers", kind = "dylib"))] +#[cfg_attr(not(target_env = "pauthtest"), link(name = "rust_test_helpers", kind = "static"))] extern "C" { #[empty_attr] fn some_definitely_unknown_symbol_which_should_be_removed(); diff --git a/tests/ui/process/nofile-limit.rs b/tests/ui/process/nofile-limit.rs index f5246856b80f2..e2f0224625a3a 100644 --- a/tests/ui/process/nofile-limit.rs +++ b/tests/ui/process/nofile-limit.rs @@ -8,6 +8,9 @@ //@ no-prefer-dynamic //@ compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static //@ ignore-backends: gcc +// aarch64-unknown-linux-pauthtest requires dynamic linking, which makes use of file descriptors. +// Setting RLIMIT_NOFILE would result in the binary failing even before main is reached. +//@ ignore-aarch64-unknown-linux-pauthtest #![feature(exit_status_error)] #![feature(rustc_private)] diff --git a/tests/ui/statics/crt-static-pauthtest.rs b/tests/ui/statics/crt-static-pauthtest.rs new file mode 100644 index 0000000000000..3b975c4e4ac02 --- /dev/null +++ b/tests/ui/statics/crt-static-pauthtest.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -C target-feature=+crt-static --target aarch64-unknown-linux-pauthtest +//@ needs-llvm-components: aarch64 +//@ only-aarch64-unknown-linux-pauthtest + + +#![feature(no_core)] +#![no_main] + +//~? ERROR pauthtest ABI is incompatible with statically linked libc diff --git a/tests/ui/statics/crt-static-pauthtest.stderr b/tests/ui/statics/crt-static-pauthtest.stderr new file mode 100644 index 0000000000000..a2a7b745196ac --- /dev/null +++ b/tests/ui/statics/crt-static-pauthtest.stderr @@ -0,0 +1,4 @@ +error: pauthtest ABI is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` + +error: aborting due to 1 previous error +