diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 7b27e496986a..6edcb275ef5b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -517,6 +517,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { return Ok(()); } + sym::cheri_address_get => { + let (size, _) = tcx.types.usize.int_size_and_signed(self.tcx); + let width = size.bits(); + + let arg = args[0].immediate(); + + let llty = self.type_ix(width); + self.call_intrinsic(format!("llvm.cheri.cap.address.get.i{width}"), &[llty], &[arg]) + } + _ if name.as_str().starts_with("simd_") => { // Unpack non-power-of-2 #[repr(packed, simd)] arguments. // This gives them the expected layout of a regular #[repr(simd)] vector. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index a18ae79f318d..2cf4cd62b48f 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -466,6 +466,11 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // not the optimization stage.) sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, + sym::cheri_without_provenance => { + let addr = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?; + ecx.write_pointer(Pointer::without_provenance(addr), dest)? + } + // We handle these here since Miri does not want to have them. sym::assert_inhabited | sym::assert_zero_valid diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 6e5fe3823ab5..a5154f340f1b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -135,7 +135,9 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::round_ties_even_f32 | sym::round_ties_even_f64 | sym::round_ties_even_f128 - | sym::const_eval_select => hir::Safety::Safe, + | sym::const_eval_select + | sym::cheri_address_get + | sym::cheri_without_provenance => hir::Safety::Safe, _ => hir::Safety::Unsafe, }; @@ -664,6 +666,13 @@ pub(crate) fn check_intrinsic_type( | sym::atomic_umin => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit), + // CHERI-specific intrinsics + sym::cheri_without_provenance => { + (1, 0, vec![tcx.types.usize], Ty::new_mut_ptr(tcx, param(0))) + } + sym::cheri_address_get => { + (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) + } other => { tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other }); return; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d54175548e30..883b5f7d1017 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -641,6 +641,9 @@ symbols! { char, char_is_ascii, char_to_digit, + cheri, + cheri_address_get, + cheri_without_provenance, child_id, child_kill, client, diff --git a/library/core/src/intrinsics/cheri.rs b/library/core/src/intrinsics/cheri.rs new file mode 100644 index 000000000000..8edda734f05e --- /dev/null +++ b/library/core/src/intrinsics/cheri.rs @@ -0,0 +1,14 @@ +//! Some intrinsics specific to CHERI systems. + +/// Create an pointer without provenance metadata from the given value. +#[inline] +#[rustc_intrinsic] +#[rustc_nounwind] +#[rustc_intrinsic_const_stable_indirect] +pub const fn cheri_without_provenance(value: usize) -> *mut T; + +/// Retrieve the address of the pointer. +#[inline] +#[rustc_intrinsic] +#[rustc_nounwind] +pub fn cheri_address_get(ptr: *const ()) -> usize; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 106cc725fee2..c1d6b4a1a0f2 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -63,6 +63,9 @@ pub mod fallback; pub mod mir; pub mod simd; +#[cfg(target_family = "cheri")] +pub mod cheri; + // These imports are used for simplifying intra-doc links #[allow(unused_imports)] #[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 2ad520b7ead7..96d8fd0eec59 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1,7 +1,7 @@ use super::*; use crate::cmp::Ordering::{Equal, Greater, Less}; use crate::intrinsics::const_eval_select; -use crate::mem::{self, SizedTypeProperties}; +use crate::mem::SizedTypeProperties; use crate::slice::{self, SliceIndex}; impl *const T { @@ -172,12 +172,21 @@ impl *const T { #[inline(always)] #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn addr(self) -> usize { - // A pointer-to-integer transmute currently has exactly the right semantics: it returns the - // address without exposing the provenance. Note that this is *not* a stable guarantee about - // transmute semantics, it relies on sysroot crates having special status. - // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the - // provenance). - unsafe { mem::transmute(self.cast::<()>()) } + + #[cfg(target_family = "cheri")] + { + crate::intrinsics::cheri::cheri_address_get(self.cast::<()>()) + } + + #[cfg(not(target_family = "cheri"))] + { + // A pointer-to-integer transmute currently has exactly the right semantics: it returns the + // address without exposing the provenance. Note that this is *not* a stable guarantee about + // transmute semantics, it relies on sysroot crates having special status. + // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the + // provenance). + unsafe { crate::mem::transmute(self.cast::<()>()) } + } } /// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 1a2a5182567b..712168098ca1 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -915,12 +915,20 @@ pub const fn dangling() -> *const T { #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn without_provenance_mut(addr: usize) -> *mut T { - // An int-to-pointer transmute currently has exactly the intended semantics: it creates a - // pointer without provenance. Note that this is *not* a stable guarantee about transmute - // semantics, it relies on sysroot crates having special status. - // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that - // pointer). - unsafe { mem::transmute(addr) } + #[cfg(target_family = "cheri")] + { + crate::intrinsics::cheri::cheri_without_provenance(addr) + } + + #[cfg(not(target_family = "cheri"))] + { + // An int-to-pointer transmute currently has exactly the intended semantics: it creates a + // pointer without provenance. Note that this is *not* a stable guarantee about transmute + // semantics, it relies on sysroot crates having special status. + // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that + // pointer). + unsafe { mem::transmute(addr) } + } } /// Creates a new pointer that is dangling, but non-null and well-aligned. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 579e2461103d..fc8a23b332c9 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -2,7 +2,7 @@ use super::*; use crate::cmp::Ordering::{Equal, Greater, Less}; use crate::intrinsics::const_eval_select; use crate::marker::PointeeSized; -use crate::mem::{self, SizedTypeProperties}; +use crate::mem::SizedTypeProperties; use crate::slice::{self, SliceIndex}; impl *mut T { @@ -160,12 +160,20 @@ impl *mut T { #[inline(always)] #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn addr(self) -> usize { - // A pointer-to-integer transmute currently has exactly the right semantics: it returns the - // address without exposing the provenance. Note that this is *not* a stable guarantee about - // transmute semantics, it relies on sysroot crates having special status. - // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the - // provenance). - unsafe { mem::transmute(self.cast::<()>()) } + #[cfg(target_family = "cheri")] + { + crate::intrinsics::cheri::cheri_address_get(self.cast::<()>()) + } + + #[cfg(not(target_family = "cheri"))] + { + // A pointer-to-integer transmute currently has exactly the right semantics: it returns the + // address without exposing the provenance. Note that this is *not* a stable guarantee about + // transmute semantics, it relies on sysroot crates having special status. + // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the + // provenance). + unsafe { crate::mem::transmute(self.cast::<()>()) } + } } /// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 5b8b44429bbc..aa79bb3a3b4c 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -44,6 +44,10 @@ const EXCEPTION_PATHS: &[&str] = &[ "library/unwind", "library/rtstartup", // Not sure what to do about this. magic stuff for mingw "library/test", // Probably should defer to unstable `std::sys` APIs. + // With the addition of CHERI-like platforms, some CHERI-specific intrinsics must be added. + "library/core/src/intrinsics/mod.rs", + // With the addition of CHERI-specific intrinsics for CHERI-like platforms, `ptr` too must have platform specific code (to use those intrinsics). + "library/core/src/ptr", // The `VaList` implementation must have platform specific code. // The Windows implementation of a `va_list` is always a character // pointer regardless of the target architecture. As a result,