Skip to content

Commit e25e3a1

Browse files
committed
Introduce aarch64-unknown-linux-pauthtest
1 parent 5bbdeaa commit e25e3a1

19 files changed

Lines changed: 459 additions & 9 deletions

File tree

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) mod gpu_offload;
88

99
use libc::{c_char, c_uint};
1010
use rustc_abi as abi;
11-
use rustc_abi::{Align, Size, WrappingRange};
11+
use rustc_abi::{Align, CanonAbi, Size, WrappingRange};
1212
use rustc_codegen_ssa::MemFlags;
1313
use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
1414
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
@@ -26,7 +26,7 @@ use rustc_sanitizers::{cfi, kcfi};
2626
use rustc_session::config::OptLevel;
2727
use rustc_span::Span;
2828
use rustc_target::callconv::{FnAbi, PassMode};
29-
use rustc_target::spec::{Arch, HasTargetSpec, SanitizerSet, Target};
29+
use rustc_target::spec::{Arch, Env, HasTargetSpec, SanitizerSet, Target};
3030
use smallvec::SmallVec;
3131
use tracing::{debug, instrument};
3232

@@ -430,6 +430,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
430430
bundles.push(kcfi_bundle);
431431
}
432432

433+
let pauth = self.ptrauth_operand_bundle(llfn, fn_abi);
434+
if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) {
435+
bundles.push(p);
436+
}
437+
433438
let invoke = unsafe {
434439
llvm::LLVMBuildInvokeWithOperandBundles(
435440
self.llbuilder,
@@ -1410,6 +1415,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
14101415
bundles.push(kcfi_bundle);
14111416
}
14121417

1418+
let pauth = self.ptrauth_operand_bundle(llfn, fn_abi);
1419+
if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) {
1420+
bundles.push(p);
1421+
}
1422+
14131423
let call = unsafe {
14141424
llvm::LLVMBuildCallWithOperandBundles(
14151425
self.llbuilder,
@@ -1857,6 +1867,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
18571867
bundles.push(kcfi_bundle);
18581868
}
18591869

1870+
let pauth = self.ptrauth_operand_bundle(llfn, fn_abi);
1871+
if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) {
1872+
bundles.push(p);
1873+
}
1874+
18601875
let callbr = unsafe {
18611876
llvm::LLVMBuildCallBr(
18621877
self.llbuilder,
@@ -1976,6 +1991,37 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19761991
kcfi_bundle
19771992
}
19781993

1994+
// Emits pauth operand bundle.
1995+
fn ptrauth_operand_bundle(
1996+
&mut self,
1997+
llfn: &'ll Value,
1998+
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
1999+
) -> Option<llvm::OperandBundleBox<'ll>> {
2000+
if self.sess().target.env != Env::Pauthtest {
2001+
return None;
2002+
}
2003+
// Pauthtest only supports extern "C" calls, filter out other ABIs.
2004+
if fn_abi?.conv != CanonAbi::C {
2005+
return None;
2006+
}
2007+
// Filter out LLVM intrinsics.
2008+
if llvm::get_value_name(llfn).starts_with(b"llvm.") {
2009+
return None;
2010+
}
2011+
2012+
// FIXME(jchlanda) operand bundles should only be attached to indirect function calls.
2013+
// However, as function signing is unstable, we end up signing too eagerly (including
2014+
// direct function calls), hence add operand bundles to all calls. We should analyze the
2015+
// call and bail out on direct calls here.
2016+
2017+
let key: u32 = 0;
2018+
let discriminator: u64 = 0;
2019+
Some(llvm::OperandBundleBox::new(
2020+
"ptrauth",
2021+
&[self.const_u32(key), self.const_u64(discriminator)],
2022+
))
2023+
}
2024+
19792025
/// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation.
19802026
#[instrument(level = "debug", skip(self))]
19812027
pub(crate) fn instrprof_increment(

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,4 +2552,11 @@ unsafe extern "C" {
25522552
Aliasee: &Value,
25532553
Name: *const c_char,
25542554
) -> &'ll Value;
2555+
2556+
pub(crate) fn LLVMRustConstPtrAuth(
2557+
ptr: *mut Value,
2558+
key: u32,
2559+
disc: u64,
2560+
addr_diversity: *mut Value,
2561+
) -> *mut Value;
25552562
}

compiler/rustc_codegen_llvm/src/llvm/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,19 @@ pub(crate) fn add_alias<'ll>(
467467
) -> &'ll Value {
468468
unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) }
469469
}
470+
471+
/// Safe wrapper for `LLVMRustConstPtrAuth`.
472+
pub(crate) fn const_ptr_auth<'ll>(
473+
ptr: &'ll Value,
474+
key: u32,
475+
disc: u64,
476+
addr_diversity: Option<&'ll Value>,
477+
) -> &'ll Value {
478+
unsafe {
479+
let addr_div_ptr = addr_diversity.map_or(std::ptr::null_mut(), |v| v as *const _ as *mut _);
480+
481+
let result = LLVMRustConstPtrAuth(ptr as *const _ as *mut _, key, disc, addr_div_ptr);
482+
483+
&*result
484+
}
485+
}

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
391391
cfg.has_reliable_f128 = match (target_arch, target_os) {
392392
// Unsupported https://github.com/llvm/llvm-project/issues/121122
393393
(Arch::AmdGpu, _) => false,
394+
// Pauthtest musl does not support 128-bit floating point math.
395+
(Arch::AArch64, _) if *target_env == Env::Pauthtest => false,
394396
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
395397
(Arch::Arm64EC, _) => false,
396398
// Selection bug <https://github.com/llvm/llvm-project/issues/95471>. This issue is closed

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,32 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
17781778
GV.setSanitizerMetadata(MD);
17791779
}
17801780

1781+
extern "C" LLVMValueRef LLVMRustConstPtrAuth(LLVMValueRef Ptr, uint32_t Key,
1782+
uint64_t Disc,
1783+
LLVMValueRef AddrDiversity) {
1784+
auto *V = unwrap<Value>(Ptr);
1785+
auto *C = dyn_cast<Constant>(V);
1786+
if (!C)
1787+
return Ptr;
1788+
if (!C->getType()->isPointerTy())
1789+
return Ptr;
1790+
if (isa<UndefValue>(C) || isa<ConstantPointerNull>(C))
1791+
return Ptr;
1792+
1793+
LLVMContext &Ctx = C->getContext();
1794+
auto *KeyC = ConstantInt::get(Type::getInt32Ty(Ctx), Key);
1795+
auto *DiscC = ConstantInt::get(Type::getInt64Ty(Ctx), Disc);
1796+
auto *PTy = cast<PointerType>(C->getType());
1797+
Constant *AddrDiv =
1798+
AddrDiversity ? dyn_cast<Constant>(unwrap<Value>(AddrDiversity))
1799+
: ConstantPointerNull::get(cast<PointerType>(C->getType()));
1800+
assert(AddrDiv && "Failed to get Address Diversity");
1801+
llvm::Type *PtrTy = llvm::PointerType::get(Ctx, PTy->getAddressSpace());
1802+
auto *DeactivationSym = llvm::Constant::getNullValue(PtrTy);
1803+
1804+
return wrap(ConstantPtrAuth::get(C, KeyC, DiscC, AddrDiv, DeactivationSym));
1805+
}
1806+
17811807
// Statically assert that the fixed metadata kind IDs declared in
17821808
// `metadata_kind.rs` match the ones actually used by LLVM.
17831809
#define FIXED_MD_KIND(VARIANT, VALUE) \

compiler/rustc_target/src/spec/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,6 +1492,7 @@ supported_targets! {
14921492
("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
14931493
("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
14941494
("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl),
1495+
("aarch64-unknown-linux-pauthtest", aarch64_unknown_linux_pauthtest),
14951496
("aarch64_be-unknown-linux-musl", aarch64_be_unknown_linux_musl),
14961497
("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
14971498
("i686-unknown-linux-musl", i686_unknown_linux_musl),
@@ -2046,6 +2047,7 @@ crate::target_spec_enum! {
20462047
P1 = "p1",
20472048
P2 = "p2",
20482049
P3 = "p3",
2050+
Pauthtest = "pauthtest",
20492051
Uclibc = "uclibc",
20502052
V5 = "v5",
20512053
Unspecified = "",
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use std::borrow::Cow;
2+
use std::collections::BTreeMap;
3+
4+
use crate::spec::{
5+
Arch, Cc, Env, FramePointer, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata,
6+
TargetOptions, base,
7+
};
8+
9+
pub(crate) fn target() -> Target {
10+
let pauthtest_sysroot = std::env::var("PAUTHTEST_SYSROOT").unwrap_or_default();
11+
12+
let pre_args = vec![
13+
"-target".into(),
14+
"aarch64-unknown-linux-pauthtest".into(),
15+
"-fuse-ld=lld".into(),
16+
Cow::Owned(format!("-L{}/usr/lib", pauthtest_sysroot)),
17+
Cow::Owned(format!("--sysroot={}", pauthtest_sysroot).into()),
18+
];
19+
let pre_link_args = BTreeMap::from([
20+
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), pre_args.clone()),
21+
(LinkerFlavor::Gnu(Cc::Yes, Lld::Yes), pre_args),
22+
]);
23+
24+
let late_args = vec![
25+
"-nostdlib".into(),
26+
Cow::Owned(format!("-Wl,--dynamic-linker={}/usr/lib/libc.so", pauthtest_sysroot)),
27+
Cow::Owned(format!("-Wl,--rpath={}/usr/lib", pauthtest_sysroot)),
28+
Cow::Owned(format!("-Wl,{}/usr/lib/crt1.o", pauthtest_sysroot)),
29+
Cow::Owned(format!("-Wl,{}/usr/lib/crti.o", pauthtest_sysroot)),
30+
Cow::Owned(format!("-Wl,{}/usr/lib/crtn.o", pauthtest_sysroot)),
31+
];
32+
let late_link_args = BTreeMap::from([
33+
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), late_args.clone()),
34+
(LinkerFlavor::Gnu(Cc::Yes, Lld::Yes), late_args),
35+
]);
36+
37+
Target {
38+
llvm_target: "aarch64-unknown-linux-pauthtest".into(),
39+
metadata: TargetMetadata {
40+
description: Some("ARM64 Linux with pauth enabled musl".into()),
41+
tier: Some(3),
42+
host_tools: Some(true),
43+
std: Some(true),
44+
},
45+
pointer_width: 64,
46+
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(),
47+
arch: Arch::AArch64,
48+
49+
options: TargetOptions {
50+
env: Env::Pauthtest,
51+
features: "+v8a,+outline-atomics,+pauth".into(),
52+
max_atomic_width: Some(128),
53+
stack_probes: StackProbeType::Inline,
54+
crt_static_default: false,
55+
crt_static_respected: false,
56+
default_uwtable: true,
57+
dynamic_linking: true,
58+
linker: Some("clang".into()),
59+
pre_link_args,
60+
late_link_args,
61+
has_rpath: true,
62+
position_independent_executables: true,
63+
// the AAPCS64 expects use of non-leaf frame pointers per
64+
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
65+
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
66+
frame_pointer: FramePointer::NonLeaf,
67+
mcount: "\u{1}_mcount".into(),
68+
..base::linux::opts()
69+
},
70+
}
71+
}

library/std/src/sys/pal/unix/stack_overflow.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,15 @@ mod imp {
409409

410410
unsafe {
411411
// this way someone on any unix-y OS can check that all these compile
412-
if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
412+
if cfg!(all(
413+
target_os = "linux",
414+
not(any(target_env = "musl", target_env = "pauthtest"))
415+
)) {
413416
install_main_guard_linux(page_size)
414-
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
417+
} else if cfg!(all(
418+
target_os = "linux",
419+
any(target_env = "musl", target_env = "pauthtest")
420+
)) {
415421
install_main_guard_linux_musl(page_size)
416422
} else if cfg!(target_os = "freebsd") {
417423
#[cfg(not(target_os = "freebsd"))]
@@ -588,7 +594,10 @@ mod imp {
588594
let mut guardsize = 0;
589595
assert_eq!(libc::pthread_attr_getguardsize(attr.as_ptr(), &mut guardsize), 0);
590596
if guardsize == 0 {
591-
if cfg!(all(target_os = "linux", target_env = "musl")) {
597+
if cfg!(all(
598+
target_os = "linux",
599+
any(target_env = "musl", target_env = "pauthtest")
600+
)) {
592601
// musl versions before 1.1.19 always reported guard
593602
// size obtained from pthread_attr_get_np as zero.
594603
// Use page size as a fallback.
@@ -604,7 +613,10 @@ mod imp {
604613
let stackaddr = stackptr.addr();
605614
ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) {
606615
Some(stackaddr - guardsize..stackaddr)
607-
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
616+
} else if cfg!(all(
617+
target_os = "linux",
618+
any(target_env = "musl", target_env = "pauthtest")
619+
)) {
608620
Some(stackaddr - guardsize..stackaddr)
609621
} else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
610622
{

library/std_detect/src/detect/os/linux/auxvec.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub(crate) struct AuxVec {
5151
/// Note that run-time feature detection is not invoked for features that can
5252
/// be detected at compile-time.
5353
///
54-
/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos}*` and
54+
/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos,pauthtest}*` and
5555
/// `*-android*` targets rather than `dlsym` it because we can safely assume
5656
/// `getauxval` is linked to the binary.
5757
/// - `*-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<usize, ()> {
125125
any(
126126
all(
127127
target_os = "linux",
128-
any(target_env = "gnu", target_env = "musl", target_env = "ohos"),
128+
any(target_env = "gnu", target_env = "musl", target_env = "ohos", target_env = "pauthtest"),
129129
),
130130
target_os = "android",
131131
) => {

library/unwind/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,20 @@ cfg_select! {
9494
}
9595
}
9696

97+
// For pauthtest explicitly reject static CRT, as the target requires dynamic
98+
// linking. Pauthtest is based on musl, the only supported unwinding mechanism
99+
// is provided by libunwind.
100+
#[cfg(target_env = "pauthtest")]
101+
cfg_select! {
102+
target_feature = "crt-static" => {
103+
compile_error!("pauthtest target only supports dynamic linking to `unwind`");
104+
}
105+
_ => {
106+
#[link(name = "unwind")]
107+
unsafe extern "C" {}
108+
}
109+
}
110+
97111
// This is the same as musl except that we default to using the system libunwind
98112
// instead of libgcc.
99113
#[cfg(target_env = "ohos")]

0 commit comments

Comments
 (0)