From b4835c371dc699561d7f56ec5c42a9635c5b6c50 Mon Sep 17 00:00:00 2001 From: S Harris <> Date: Mon, 25 Aug 2025 15:47:16 +0200 Subject: [PATCH] cheri: Modify LLVM wrapper to support CHERI tag options for memcpy and memmove Co-authored-by: Edoardo Marangoni --- .cirrus.yml | 11 +++- cheri/gen_bootstrap.sh | 2 +- compiler/rustc_codegen_gcc/src/builder.rs | 4 +- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 3 +- compiler/rustc_codegen_llvm/src/abi.rs | 3 ++ compiler/rustc_codegen_llvm/src/builder.rs | 8 ++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 21 ++++++++ compiler/rustc_codegen_llvm/src/va_arg.rs | 3 +- compiler/rustc_codegen_ssa/src/common.rs | 7 +++ compiler/rustc_codegen_ssa/src/mir/block.rs | 3 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 8 +-- .../rustc_codegen_ssa/src/mir/statement.rs | 4 +- .../rustc_codegen_ssa/src/traits/builder.rs | 9 +++- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 54 +++++++++++++------ 14 files changed, 111 insertions(+), 29 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index ede0a8477012..39e467804011 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -32,7 +32,12 @@ pr_check_commits_task: x_check_task: skip: $CIRRUS_PR == "" name: (PR) Run ./x check - depends_on: (PR) Check commits structure + # TODO(xdoardo): Figure out when it makes sense to have this dependency, or + # how that dependency should actually work. Having this dependency would + # pretty much mean making every PR that merges changes on `beta` to `master` + # to have failing CI, which would be the reason why we want to make PRs and + # not direct pushes in the first place. + # depends_on: (PR) Check commits structure timeout_in: 240m gce_instance: &arm_vm image_project: ubuntu-os-cloud @@ -54,6 +59,8 @@ x_check_task: - export CCACHE_REMOTE_STORAGE="http://${CIRRUS_HTTP_CACHE_HOST}/${CIRRUS_OS}/" - export CCACHE_REMOTE_ONLY=1 - env - test_script: CC="clang" CXX="clang++" ./x check + pull_master_script: git fetch origin master + tidy_script: CC="clang" CXX="clang++" ./x test tidy + check_script: CC="clang" CXX="clang++" ./x check # -- End PR tasks diff --git a/cheri/gen_bootstrap.sh b/cheri/gen_bootstrap.sh index 69d7a40b612d..88029d55b783 100755 --- a/cheri/gen_bootstrap.sh +++ b/cheri/gen_bootstrap.sh @@ -17,7 +17,7 @@ change-id = 140732 ccache = true [rust] -#channel = "nightly" +channel = "beta" #codegen-backends = ["llvm"] #debug = true #debuginfo-level = 2 diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 4aee211e2efa..fd74b6f6e75c 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -12,7 +12,7 @@ use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout, WrappingRange}; use rustc_apfloat::{Float, Round, Status, ieee}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{ - AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, + AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, PreserveCheriTags, }; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -1369,6 +1369,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _src_align: Align, size: RValue<'gcc>, flags: MemFlags, + _preserve_cheri_tags: PreserveCheriTags, ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported"); let size = self.intcast(size, self.type_size_t(), false); @@ -1391,6 +1392,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _src_align: Align, size: RValue<'gcc>, flags: MemFlags, + _preserve_cheri_flags: PreserveCheriTags, ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memmove not supported"); let size = self.intcast(size, self.type_size_t(), false); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 0753ac1aeb84..a68256d67a57 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -12,7 +12,7 @@ use rustc_abi::ExternAbi; use rustc_abi::{BackendRepr, HasDataLayout}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; -use rustc_codegen_ssa::common::IntPredicate; +use rustc_codegen_ssa::common::{IntPredicate, PreserveCheriTags}; use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; @@ -771,6 +771,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { scratch_align, bx.const_usize(self.layout.size.bytes()), MemFlags::empty(), + PreserveCheriTags::Unknown, ); bx.lifetime_end(scratch, scratch_size); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 009e7e2487b6..d70174b2e68a 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -7,6 +7,7 @@ use rustc_abi::{ X86Call, }; use rustc_codegen_ssa::MemFlags; +use rustc_codegen_ssa::common::PreserveCheriTags; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; @@ -238,6 +239,8 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { scratch_align, bx.const_usize(copy_bytes), MemFlags::empty(), + // Handling of CHERI capabilities could probably be more efficient. + PreserveCheriTags::Unknown, ); bx.lifetime_end(llscratch, scratch_size); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index da2a153d819f..c163f516ac09 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -35,7 +35,7 @@ use crate::attributes; use crate::common::Funclet; use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; use crate::llvm::{ - self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True, + self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True, PreserveCheriTags }; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -1106,9 +1106,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src_align: Align, size: &'ll Value, flags: MemFlags, + preserve_tags: rustc_codegen_ssa::common::PreserveCheriTags, ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported"); let size = self.intcast(size, self.type_isize(), false); + let preserve_tags = PreserveCheriTags::from_generic(preserve_tags); let is_volatile = flags.contains(MemFlags::VOLATILE); unsafe { llvm::LLVMRustBuildMemCpy( @@ -1118,6 +1120,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src, src_align.bytes() as c_uint, size, + preserve_tags, is_volatile, ); } @@ -1131,9 +1134,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src_align: Align, size: &'ll Value, flags: MemFlags, + preserve_tags: rustc_codegen_ssa::common::PreserveCheriTags, ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memmove not supported"); let size = self.intcast(size, self.type_isize(), false); + let preserve_tags = PreserveCheriTags::from_generic(preserve_tags); let is_volatile = flags.contains(MemFlags::VOLATILE); unsafe { llvm::LLVMRustBuildMemMove( @@ -1143,6 +1148,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src, src_align.bytes() as c_uint, size, + preserve_tags, is_volatile, ); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2443194ff483..485518b2f082 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -741,6 +741,25 @@ pub(crate) enum Opcode { CatchSwitch = 65, } +/// LLVMPreserveCheriTags +#[derive(Copy, Clone)] +#[repr(C)] +pub(crate) enum PreserveCheriTags { + Unknown, + Required, + Unnecessary, +} + +impl PreserveCheriTags { + pub(crate) fn from_generic(value: rustc_codegen_ssa::common::PreserveCheriTags) -> Self { + match value { + rustc_codegen_ssa::common::PreserveCheriTags::Unknown => PreserveCheriTags::Unknown, + rustc_codegen_ssa::common::PreserveCheriTags::Required => PreserveCheriTags::Required, + rustc_codegen_ssa::common::PreserveCheriTags::Unnecessary => PreserveCheriTags::Unnecessary, + } + } +} + unsafe extern "C" { type Opaque; } @@ -1933,6 +1952,7 @@ unsafe extern "C" { Src: &'a Value, SrcAlign: c_uint, Size: &'a Value, + PreserveTags: PreserveCheriTags, IsVolatile: bool, ) -> &'a Value; pub(crate) fn LLVMRustBuildMemMove<'a>( @@ -1942,6 +1962,7 @@ unsafe extern "C" { Src: &'a Value, SrcAlign: c_uint, Size: &'a Value, + PreserveTags: PreserveCheriTags, IsVolatile: bool, ) -> &'a Value; pub(crate) fn LLVMRustBuildMemSet<'a>( diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ce079f3cb0af..e1487ffa839f 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1,6 +1,6 @@ use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size, TyAndLayout}; use rustc_codegen_ssa::MemFlags; -use rustc_codegen_ssa::common::IntPredicate; +use rustc_codegen_ssa::common::{IntPredicate, PreserveCheriTags}; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods, @@ -735,6 +735,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( src_align, bx.const_u32(layout.layout.size().bytes() as u32), MemFlags::empty(), + PreserveCheriTags::Unknown, ); tmp } else { diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index a6fd6c763edd..b59519a0eccd 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -59,6 +59,13 @@ pub enum AtomicRmwBinOp { AtomicUMin, } +#[derive(Copy, Clone, Debug)] +pub enum PreserveCheriTags { + Unknown, + Required, + Unnecessary, +} + #[derive(Copy, Clone, Debug)] pub enum SynchronizationScope { SingleThread, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e96590441fa4..6c69e4bfad24 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -21,7 +21,7 @@ use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized}; use super::place::{PlaceRef, PlaceValue}; use super::{CachedLlbb, FunctionCx, LocalRef}; use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization}; -use crate::common::{self, IntPredicate}; +use crate::common::{self, IntPredicate, PreserveCheriTags}; use crate::errors::CompilerBuiltinsCannotCall; use crate::traits::*; use crate::{MemFlags, meth}; @@ -1601,6 +1601,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { align, bx.const_usize(copy_bytes), MemFlags::empty(), + PreserveCheriTags::Unknown, ); // ...and then load it with the ABI type. llval = load_cast(bx, cast, llscratch, scratch_align); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index fc95f62b4a43..f48f713f79e6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -8,7 +8,7 @@ use rustc_span::sym; use super::FunctionCx; use super::operand::OperandRef; use super::place::PlaceRef; -use crate::common::{AtomicRmwBinOp, SynchronizationScope}; +use crate::common::{AtomicRmwBinOp, SynchronizationScope, PreserveCheriTags}; use crate::errors::InvalidMonomorphization; use crate::traits::*; use crate::{MemFlags, meth, size_of_val}; @@ -27,10 +27,12 @@ fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let align = layout.align.abi; let size = bx.mul(bx.const_usize(size.bytes()), count); let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + // Handling of CHERI capabilities could probably be more efficient. + let preserve_tags = PreserveCheriTags::Unknown; if allow_overlap { - bx.memmove(dst, align, src, align, size, flags); + bx.memmove(dst, align, src, align, size, flags, preserve_tags); } else { - bx.memcpy(dst, align, src, align, size, flags); + bx.memcpy(dst, align, src, align, size, flags, preserve_tags); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index f164e0f91237..7061821c652c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -3,6 +3,7 @@ use rustc_middle::span_bug; use tracing::instrument; use super::{FunctionCx, LocalRef}; +use crate::common::PreserveCheriTags; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -90,7 +91,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let align = pointee_layout.align; let dst = dst_val.immediate(); let src = src_val.immediate(); - bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty()); + // Handling of CHERI capabilities could probably be more efficient. + bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty(), PreserveCheriTags::Unknown); } mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 4b18146863bf..be9b9aa40410 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -19,7 +19,9 @@ use super::misc::MiscCodegenMethods; use super::type_::{ArgAbiBuilderMethods, BaseTypeCodegenMethods, LayoutTypeCodegenMethods}; use super::{CodegenMethods, StaticBuilderMethods}; use crate::MemFlags; -use crate::common::{AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; +use crate::common::{ + PreserveCheriTags, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, +}; use crate::mir::operand::{OperandRef, OperandValue}; use crate::mir::place::{PlaceRef, PlaceValue}; @@ -424,6 +426,7 @@ pub trait BuilderMethods<'a, 'tcx>: src_align: Align, size: Self::Value, flags: MemFlags, + preserve_tags: PreserveCheriTags, ); fn memmove( &mut self, @@ -433,6 +436,7 @@ pub trait BuilderMethods<'a, 'tcx>: src_align: Align, size: Self::Value, flags: MemFlags, + preserve_tags: PreserveCheriTags, ); fn memset( &mut self, @@ -480,7 +484,8 @@ pub trait BuilderMethods<'a, 'tcx>: temp.val.store_with_flags(self, dst.with_type(layout), flags); } else if !layout.is_zst() { let bytes = self.const_usize(layout.size.bytes()); - self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags); + self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, + PreserveCheriTags::Unknown); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 588d867bbbf4..76acb64fdf80 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1564,23 +1564,47 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut, return true; } -extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, - unsigned DstAlign, LLVMValueRef Src, - unsigned SrcAlign, - LLVMValueRef Size, - bool IsVolatile) { - return wrap(unwrap(B)->CreateMemCpy(unwrap(Dst), MaybeAlign(DstAlign), - unwrap(Src), MaybeAlign(SrcAlign), - unwrap(Size), IsVolatile)); +enum class LLVMPreserveCheriTags { + Unknown, + Required, + Unnecessary, +}; + +static PreserveCheriTags fromRust(LLVMPreserveCheriTags PreserveTags) { + switch (PreserveTags) { + case LLVMPreserveCheriTags::Unknown: + return PreserveCheriTags::Unknown; + case LLVMPreserveCheriTags::Required: + return PreserveCheriTags::Required; + case LLVMPreserveCheriTags::Unnecessary: + return PreserveCheriTags::Unnecessary; + } + + report_fatal_error("Invalid LLVMPreserveCheriTags value!"); } -extern "C" LLVMValueRef -LLVMRustBuildMemMove(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, - LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, - bool IsVolatile) { - return wrap(unwrap(B)->CreateMemMove(unwrap(Dst), MaybeAlign(DstAlign), - unwrap(Src), MaybeAlign(SrcAlign), - unwrap(Size), IsVolatile)); +extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, + LLVMValueRef Dst, unsigned DstAlign, + LLVMValueRef Src, unsigned SrcAlign, + LLVMValueRef Size, LLVMPreserveCheriTags PreserveTags, + bool IsVolatile) { + return wrap(unwrap(B)->CreateMemCpy( + unwrap(Dst), MaybeAlign(DstAlign), + unwrap(Src), MaybeAlign(SrcAlign), + unwrap(Size), fromRust(PreserveTags), + IsVolatile)); +} + +extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B, + LLVMValueRef Dst, unsigned DstAlign, + LLVMValueRef Src, unsigned SrcAlign, + LLVMValueRef Size, LLVMPreserveCheriTags PreserveTags, + bool IsVolatile) { + return wrap(unwrap(B)->CreateMemMove( + unwrap(Dst), MaybeAlign(DstAlign), + unwrap(Src), MaybeAlign(SrcAlign), + unwrap(Size), fromRust(PreserveTags), + IsVolatile)); } extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst,