Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
416 changes: 416 additions & 0 deletions .github/workflows/fork-arm64e.yml

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,13 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
}
}

if has_default_arm64e_ptrauth(sess) {
to_add.push(llvm::CreateAttrString(cx.llcx, "ptrauth-auth-traps"));
to_add.push(llvm::CreateAttrString(cx.llcx, "ptrauth-calls"));
to_add.push(llvm::CreateAttrString(cx.llcx, "ptrauth-indirect-gotos"));
to_add.push(llvm::CreateAttrString(cx.llcx, "ptrauth-returns"));
}

let function_features = function_features
.iter()
// Convert to LLVMFeatures and filter out unavailable ones
Expand Down Expand Up @@ -613,3 +620,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<&String> {
tcx.wasm_import_module_map(id.krate).get(&id)
}

pub(crate) fn has_default_arm64e_ptrauth(sess: &Session) -> bool {
sess.target.is_apple_arm64e()
&& sess.unstable_target_features.contains(&sym::paca)
&& sess.unstable_target_features.contains(&sym::pacg)
}
14 changes: 12 additions & 2 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ fn write_output_file<'ll>(
} else {
std::ptr::null()
};

// LLVM may devirtualize indirect arm64e calls into direct calls after we
// attached ptrauth operand bundles. Strip bundles from call shapes LLVM
// cannot lower just before object/assembly emission.
llvm::strip_unsupported_ptrauth_bundles(m);

let result = unsafe {
let pm = llvm::LLVMCreatePassManager();
llvm::LLVMAddAnalysisPasses(target, pm);
Expand Down Expand Up @@ -742,8 +748,12 @@ pub(crate) unsafe fn llvm_optimize(
}

if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Device) {
let cx =
SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size);
let cx = SimpleCx::new(
module.module_llvm.llmod(),
module.module_llvm.llcx,
cgcx.pointer_size,
false,
);
for func in cx.get_functions() {
let offload_kernel = "offload-kernel";
if attributes::has_string_attr(func, offload_kernel) {
Expand Down
35 changes: 31 additions & 4 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,14 @@ impl<'a, 'll> SBuilder<'a, 'll> {

let args = self.check_call("call", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
let mut bundles: SmallVec<[_; 3]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
let ptrauth_bundle = self.ptrauth_operand_bundle(llfn);
if let Some(ptrauth_bundle) = ptrauth_bundle.as_ref().map(|b| b.as_ref()) {
bundles.push(ptrauth_bundle);
}

let call = unsafe {
llvm::LLVMBuildCallWithOperandBundles(
Expand Down Expand Up @@ -187,6 +191,18 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
load
}
}

fn ptrauth_operand_bundle(&mut self, llfn: &'ll Value) -> Option<llvm::OperandBundleBox<'ll>> {
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
if self.cx.is_apple_arm64e() && is_indirect_call {
Some(llvm::OperandBundleBox::new(
"ptrauth",
&[self.cx.get_const_i32(0), self.cx.get_const_i64(0)],
))
} else {
None
}
}
}

/// Empty string, to be used where LLVM expects an instruction name, indicating
Expand Down Expand Up @@ -415,10 +431,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {

let args = self.check_call("invoke", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
let mut bundles: SmallVec<[_; 3]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
let ptrauth_bundle = self.ptrauth_operand_bundle(llfn);
if let Some(ptrauth_bundle) = ptrauth_bundle.as_ref().map(|b| b.as_ref()) {
bundles.push(ptrauth_bundle);
}

// Emit CFI pointer type membership test
self.cfi_type_test(fn_attrs, fn_abi, instance, llfn);
Expand Down Expand Up @@ -1388,10 +1408,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {

let args = self.check_call("call", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
let mut bundles: SmallVec<[_; 3]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
let ptrauth_bundle = self.ptrauth_operand_bundle(llfn);
if let Some(ptrauth_bundle) = ptrauth_bundle.as_ref().map(|b| b.as_ref()) {
bundles.push(ptrauth_bundle);
}

// Emit CFI pointer type membership test
self.cfi_type_test(caller_attrs, fn_abi, callee_instance, llfn);
Expand Down Expand Up @@ -1835,7 +1859,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {

let args = self.check_call("callbr", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
let mut bundles: SmallVec<[_; 3]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
Expand All @@ -1850,6 +1874,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
}

let callbr = unsafe {
// LLVM cannot lower arm64e ptrauth operand bundles on callbr yet.
// Keep the ordinary call/invoke arm64e coverage, but leave asm-goto
// style control flow as a follow-up.
llvm::LLVMBuildCallBr(
self.llbuilder,
llty,
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_codegen_llvm/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,9 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
value
}
}
GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
GlobalAlloc::Function { instance, .. } => {
self.arm64e_fn_ptr_for_data(self.get_fn_addr(instance))
}
GlobalAlloc::VTable(ty, dyn_ty) => {
let alloc = self
.tcx
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,24 @@ impl<'ll> CodegenCx<'ll, '_> {
unsafe { llvm::LLVMConstPointerCast(val, ty) }
}

pub(crate) fn arm64e_fn_ptr_for_data(&self, fn_addr: &'ll Value) -> &'ll Value {
if !self.is_apple_arm64e() {
return fn_addr;
}

let fn_addr = self.const_pointercast(fn_addr, self.type_ptr());
unsafe {
// ConstantPtrAuth requires an i64 discriminator and a pointer-typed
// address discriminator, even when both are effectively "zero".
llvm::LLVMConstantPtrAuth(
fn_addr,
self.get_const_i32(0),
self.get_const_i64(0),
self.const_null(self.type_ptr()),
)
}
}

/// Create a global variable.
///
/// The returned global variable is a pointer in the default address space for globals.
Expand Down
59 changes: 56 additions & 3 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub(crate) struct SCx<'ll> {
pub llmod: &'ll llvm::Module,
pub llcx: &'ll llvm::Context,
pub isize_ty: &'ll Type,
pub is_apple_arm64e: bool,
}

impl<'ll> Borrow<SCx<'ll>> for FullCx<'ll, '_> {
Expand Down Expand Up @@ -185,7 +186,12 @@ pub(crate) unsafe fn create_module<'ll>(
let mod_name = SmallCStr::new(mod_name);
let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) };

let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size());
let cx = SimpleCx::new(
llmod,
llcx,
tcx.data_layout.pointer_size(),
attributes::has_default_arm64e_ptrauth(sess),
);

let mut target_data_layout = sess.target.data_layout.to_string();
let llvm_version = llvm_util::get_version();
Expand Down Expand Up @@ -426,6 +432,39 @@ pub(crate) unsafe fn create_module<'ll>(
}
}

if attributes::has_default_arm64e_ptrauth(sess) {
let ptrauth_abi_version = unsafe {
llvm::LLVMMDNodeInContext2(
llcx,
[llvm::LLVMMDNodeInContext2(
llcx,
[
llvm::LLVMValueAsMetadata(llvm::LLVMConstInt(
llvm::LLVMInt32TypeInContext(llcx),
0,
llvm::FALSE,
)),
llvm::LLVMValueAsMetadata(llvm::LLVMConstInt(
llvm::LLVMInt1TypeInContext(llcx),
0,
llvm::FALSE,
)),
]
.as_ptr(),
2,
)]
.as_ptr(),
1,
)
};
llvm::add_module_flag_metadata(
llmod,
llvm::ModuleFlagMergeBehavior::AppendUnique,
"ptrauth.abi-version",
ptrauth_abi_version,
);
}

// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
llvm::add_module_flag_u32(
Expand Down Expand Up @@ -621,7 +660,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
GenericCx(
FullCx {
tcx,
scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()),
scx: SimpleCx::new(
llmod,
llcx,
tcx.data_layout.pointer_size(),
attributes::has_default_arm64e_ptrauth(tcx.sess),
),
use_dll_storage_attrs,
tls_model,
codegen_unit,
Expand Down Expand Up @@ -749,13 +793,18 @@ impl<'ll> SimpleCx<'ll> {
llmod: &'ll llvm::Module,
llcx: &'ll llvm::Context,
pointer_size: Size,
is_apple_arm64e: bool,
) -> Self {
let isize_ty = llvm::LLVMIntTypeInContext(llcx, pointer_size.bits() as c_uint);
Self(SCx { llmod, llcx, isize_ty }, PhantomData)
Self(SCx { llmod, llcx, isize_ty, is_apple_arm64e }, PhantomData)
}
}

impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
pub(crate) fn is_apple_arm64e(&self) -> bool {
(**self).borrow().is_apple_arm64e
}

pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
llvm::LLVMMetadataAsValue(self.llcx(), metadata)
}
Expand Down Expand Up @@ -836,6 +885,10 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
get_fn(self, instance)
}

fn get_fn_addr_for_data(&self, instance: Instance<'tcx>) -> &'ll Value {
self.arm64e_fn_ptr_for_data(get_fn(self, instance))
}

fn eh_personality(&self) -> &'ll Value {
// The exception handling personality function.
//
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,12 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
methods: &[AllocatorMethod],
) -> ModuleLlvm {
let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
let cx =
SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size());
let cx = SimpleCx::new(
module_llvm.llmod(),
&module_llvm.llcx,
tcx.data_layout.pointer_size(),
attributes::has_default_arm64e_ptrauth(tcx.sess),
);
unsafe {
allocator::codegen(tcx, cx, module_name, methods);
}
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,12 @@ unsafe extern "C" {
ConstantVals: *const &'a Value,
Count: c_uint,
) -> &'a Value;
pub(crate) fn LLVMConstantPtrAuth<'a>(
Ptr: &'a Value,
Key: &'a Value,
Disc: &'a Value,
AddrDisc: &'a Value,
) -> &'a Value;
pub(crate) fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;

// Constant expressions
Expand Down Expand Up @@ -2185,6 +2191,14 @@ unsafe extern "C" {
ValueLen: size_t,
);

pub(crate) fn LLVMRustAddModuleFlagMetadata(
M: &Module,
MergeBehavior: ModuleFlagMergeBehavior,
Name: *const c_char,
NameLen: size_t,
Value: &Metadata,
);

pub(crate) fn LLVMRustDIBuilderCreateCompileUnit<'a>(
Builder: &DIBuilder<'a>,
Lang: c_uint,
Expand Down Expand Up @@ -2494,6 +2508,7 @@ unsafe extern "C" {
pub(crate) fn LLVMRustBufferFree(p: &'static mut Buffer);
pub(crate) fn LLVMRustModuleCost(M: &Module) -> u64;
pub(crate) fn LLVMRustModuleInstructionStats(M: &Module) -> u64;
pub(crate) fn LLVMRustStripUnsupportedPtrauthBundles(M: &Module);

pub(crate) fn LLVMRustModuleSerialize(M: &Module, is_thin: bool) -> &'static mut Buffer;
pub(crate) fn LLVMRustCreateThinLTOData(
Expand Down
23 changes: 23 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,29 @@ pub(crate) fn add_module_flag_str(
}
}

pub(crate) fn add_module_flag_metadata(
module: &Module,
merge_behavior: ModuleFlagMergeBehavior,
key: &str,
value: &Metadata,
) {
unsafe {
LLVMRustAddModuleFlagMetadata(
module,
merge_behavior,
key.as_c_char_ptr(),
key.len(),
value,
);
}
}

pub(crate) fn strip_unsupported_ptrauth_bundles(module: &Module) {
unsafe {
LLVMRustStripUnsupportedPtrauthBundles(module);
}
}

pub(crate) fn set_dllimport_storage_class<'ll>(v: &'ll Value) {
unsafe {
LLVMSetDLLStorageClass(v, DLLStorageClass::DllImport);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,9 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
file.set_sub_architecture(sub_architecture);
if sess.target.is_like_darwin {
if macho_is_arm64e(&sess.target) {
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
file.set_macho_cpu_subtype(
object::macho::CPU_SUBTYPE_ARM64E | object::macho::CPU_SUBTYPE_LIB64,
);
}

file.set_macho_build_version(macho_object_build_version_for_target(sess))
Expand Down Expand Up @@ -444,7 +446,7 @@ fn macho_object_build_version_for_target(sess: &Session) -> object::write::MachO

/// Is Apple's CPU subtype `arm64e`s
fn macho_is_arm64e(target: &Target) -> bool {
target.llvm_target.starts_with("arm64e")
target.is_apple_arm64e()
}

pub(crate) enum MetadataPosition {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_for_data(instance);

let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
return Some(entry_fn);
Expand Down
Loading
Loading