Skip to content

Commit d331cb7

Browse files
committed
Auto merge of #88354 - Jmc18134:hint-space-pauth-opt, r=nagisa
Add codegen option for branch protection and pointer authentication on AArch64 The branch-protection codegen option enables the use of hint-space pointer authentication code for AArch64 targets.
2 parents 78fd0f6 + 984ca46 commit d331cb7

File tree

13 files changed

+202
-6
lines changed

13 files changed

+202
-6
lines changed

compiler/rustc_codegen_llvm/src/context.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_middle::ty::layout::{
2121
};
2222
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
2323
use rustc_middle::{bug, span_bug};
24-
use rustc_session::config::{CFGuard, CrateType, DebugInfo};
24+
use rustc_session::config::{BranchProtection, CFGuard, CrateType, DebugInfo, PAuthKey, PacRet};
2525
use rustc_session::Session;
2626
use rustc_span::source_map::Span;
2727
use rustc_span::symbol::Symbol;
@@ -242,6 +242,34 @@ pub unsafe fn create_module<'ll>(
242242
}
243243
}
244244

245+
if sess.target.arch == "aarch64" {
246+
let BranchProtection { bti, pac_ret: pac } = sess.opts.debugging_opts.branch_protection;
247+
248+
llvm::LLVMRustAddModuleFlag(
249+
llmod,
250+
"branch-target-enforcement\0".as_ptr().cast(),
251+
bti.into(),
252+
);
253+
254+
llvm::LLVMRustAddModuleFlag(
255+
llmod,
256+
"sign-return-address\0".as_ptr().cast(),
257+
pac.is_some().into(),
258+
);
259+
let pac_opts = pac.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
260+
llvm::LLVMRustAddModuleFlag(
261+
llmod,
262+
"sign-return-address-all\0".as_ptr().cast(),
263+
pac_opts.leaf.into(),
264+
);
265+
let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true };
266+
llvm::LLVMRustAddModuleFlag(
267+
llmod,
268+
"sign-return-address-with-bkey\0".as_ptr().cast(),
269+
is_bkey.into(),
270+
);
271+
}
272+
245273
llmod
246274
}
247275

compiler/rustc_codegen_llvm/src/declare.rs

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ fn declare_raw_fn<'ll>(
4747

4848
attributes::default_optimisation_attrs(cx.tcx.sess, llfn);
4949
attributes::non_lazy_bind(cx.sess(), llfn);
50+
5051
llfn
5152
}
5253

compiler/rustc_interface/src/tests.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ use rustc_session::config::{build_configuration, build_session_options, to_crate
88
use rustc_session::config::{
99
rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
1010
};
11-
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
1211
use rustc_session::config::{
13-
Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel,
12+
BranchProtection, Externs, OutputType, OutputTypes, PAuthKey, PacRet, SymbolManglingVersion,
13+
WasiExecModel,
1414
};
15+
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
1516
use rustc_session::lint::Level;
1617
use rustc_session::search_paths::SearchPath;
1718
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
@@ -717,6 +718,10 @@ fn test_debugging_options_tracking_hash() {
717718
tracked!(asm_comments, true);
718719
tracked!(assume_incomplete_release, true);
719720
tracked!(binary_dep_depinfo, true);
721+
tracked!(
722+
branch_protection,
723+
BranchProtection { bti: true, pac_ret: Some(PacRet { leaf: true, key: PAuthKey::B }) }
724+
);
720725
tracked!(chalk, true);
721726
tracked!(codegen_backend, Some("abc".to_string()));
722727
tracked!(crate_attr, vec!["abc".to_string()]);

compiler/rustc_session/src/config.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,30 @@ impl Passes {
843843
}
844844
}
845845

846+
#[derive(Clone, Copy, Hash, Debug, PartialEq)]
847+
pub enum PAuthKey {
848+
A,
849+
B,
850+
}
851+
852+
#[derive(Clone, Copy, Hash, Debug, PartialEq)]
853+
pub struct PacRet {
854+
pub leaf: bool,
855+
pub key: PAuthKey,
856+
}
857+
858+
#[derive(Clone, Copy, Hash, Debug, PartialEq)]
859+
pub struct BranchProtection {
860+
pub bti: bool,
861+
pub pac_ret: Option<PacRet>,
862+
}
863+
864+
impl Default for BranchProtection {
865+
fn default() -> Self {
866+
BranchProtection { bti: false, pac_ret: None }
867+
}
868+
}
869+
846870
pub const fn default_lib_output() -> CrateType {
847871
CrateType::Rlib
848872
}
@@ -2497,9 +2521,9 @@ impl PpMode {
24972521
crate mod dep_tracking {
24982522
use super::LdImpl;
24992523
use super::{
2500-
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2501-
LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2502-
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2524+
BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage,
2525+
LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes,
2526+
SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
25032527
};
25042528
use crate::lint;
25052529
use crate::options::WasiExecModel;
@@ -2593,6 +2617,7 @@ crate mod dep_tracking {
25932617
OutputType,
25942618
RealFileName,
25952619
LocationDetail,
2620+
BranchProtection,
25962621
);
25972622

25982623
impl<T1, T2> DepTrackingHash for (T1, T2)

compiler/rustc_session/src/options.rs

+30
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ mod desc {
415415
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
416416
pub const parse_stack_protector: &str =
417417
"one of (`none` (default), `basic`, `strong`, or `all`)";
418+
pub const parse_branch_protection: &str =
419+
"a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`";
418420
}
419421

420422
mod parse {
@@ -955,6 +957,32 @@ mod parse {
955957
}
956958
true
957959
}
960+
961+
crate fn parse_branch_protection(slot: &mut BranchProtection, v: Option<&str>) -> bool {
962+
match v {
963+
Some(s) => {
964+
for opt in s.split(',') {
965+
match opt {
966+
"bti" => slot.bti = true,
967+
"pac-ret" if slot.pac_ret.is_none() => {
968+
slot.pac_ret = Some(PacRet { leaf: false, key: PAuthKey::A })
969+
}
970+
"leaf" => match slot.pac_ret.as_mut() {
971+
Some(pac) => pac.leaf = true,
972+
_ => return false,
973+
},
974+
"b-key" => match slot.pac_ret.as_mut() {
975+
Some(pac) => pac.key = PAuthKey::B,
976+
_ => return false,
977+
},
978+
_ => return false,
979+
};
980+
}
981+
}
982+
_ => return false,
983+
}
984+
true
985+
}
958986
}
959987

960988
options! {
@@ -1096,6 +1124,8 @@ options! {
10961124
(default: no)"),
10971125
borrowck: String = ("migrate".to_string(), parse_string, [UNTRACKED],
10981126
"select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"),
1127+
branch_protection: BranchProtection = (BranchProtection::default(), parse_branch_protection, [TRACKED],
1128+
"set options for branch target identification and pointer authentication on AArch64"),
10991129
cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED],
11001130
"the codegen unit partitioning strategy to use"),
11011131
chalk: bool = (false, parse_bool, [TRACKED],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# `branch-protection`
2+
3+
This option lets you enable branch authentication instructions on AArch64.
4+
This option is ignored for non-AArch64 architectures.
5+
It takes some combination of the following values, separated by a `,`.
6+
7+
- `pac-ret` - Enable pointer authentication for non-leaf functions.
8+
- `leaf` - Enable pointer authentication for all functions, including leaf functions.
9+
- `b-key` - Sign return addresses with key B, instead of the default key A.
10+
- `bti` - Enable branch target identification.
11+
12+
`leaf` and `b-key` are only valid if `pac-ret` was previously specified.
13+
For example, `-Z branch-protection=bti,pac-ret,leaf` is valid, but
14+
`-Z branch-protection=bti,leaf,pac-ret` is not.
15+
16+
Rust's standard library does not ship with BTI or pointer authentication enabled by default.
17+
In Cargo projects the standard library can be recompiled with pointer authentication using the nightly
18+
[build-std](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) feature.
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Test that PAC instructions are emitted when branch-protection is specified.
2+
3+
// min-llvm-version: 10.0.1
4+
// assembly-output: emit-asm
5+
// compile-flags: --target aarch64-unknown-linux-gnu
6+
// compile-flags: -Z branch-protection=pac-ret,leaf
7+
// needs-llvm-components: aarch64
8+
9+
#![feature(no_core, lang_items)]
10+
#![no_std]
11+
#![no_core]
12+
#![crate_type = "lib"]
13+
14+
#[lang = "sized"]
15+
trait Sized {}
16+
17+
// CHECK: hint #25
18+
// CHECK: hint #29
19+
#[no_mangle]
20+
pub fn test() -> u8 {
21+
42
22+
}

src/test/codegen/branch-protection.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Test that the correct module flags are emitted with different branch protection flags.
2+
3+
// revisions: bti pac-ret leaf b-key
4+
// min-llvm-version: 12.0.0
5+
// needs-llvm-components: aarch64
6+
// [bti] compile-flags: -Z branch-protection=bti
7+
// [pac-ret] compile-flags: -Z branch-protection=pac-ret
8+
// [leaf] compile-flags: -Z branch-protection=pac-ret,leaf
9+
// [b-key] compile-flags: -Z branch-protection=pac-ret,b-key
10+
// compile-flags: --target aarch64-unknown-linux-gnu
11+
12+
#![crate_type = "lib"]
13+
#![feature(no_core, lang_items)]
14+
#![no_core]
15+
16+
#[lang="sized"]
17+
trait Sized { }
18+
19+
// A basic test function.
20+
pub fn test() {
21+
}
22+
23+
// bti: !"branch-target-enforcement", i32 1
24+
// bti: !"sign-return-address", i32 0
25+
// bti: !"sign-return-address-all", i32 0
26+
// bti: !"sign-return-address-with-bkey", i32 0
27+
28+
// pac-ret: !"branch-target-enforcement", i32 0
29+
// pac-ret: !"sign-return-address", i32 1
30+
// pac-ret: !"sign-return-address-all", i32 0
31+
// pac-ret: !"sign-return-address-with-bkey", i32 0
32+
33+
// leaf: !"branch-target-enforcement", i32 0
34+
// leaf: !"sign-return-address", i32 1
35+
// leaf: !"sign-return-address-all", i32 1
36+
// leaf: !"sign-return-address-with-bkey", i32 0
37+
38+
// b-key: !"branch-target-enforcement", i32 0
39+
// b-key: !"sign-return-address", i32 1
40+
// b-key: !"sign-return-address-all", i32 0
41+
// b-key: !"sign-return-address-with-bkey", i32 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-include ../tools.mk
2+
3+
# only-aarch64
4+
5+
all:
6+
$(COMPILE_OBJ) $(TMPDIR)/test.o test.c
7+
$(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
8+
$(RUSTC) -Z branch-protection=bti,pac-ret,leaf test.rs
9+
$(call RUN,test)
10+
11+
$(COMPILE_OBJ) $(TMPDIR)/test.o test.c -mbranch-protection=bti+pac-ret+leaf
12+
$(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
13+
$(RUSTC) -Z branch-protection=bti,pac-ret,leaf test.rs
14+
$(call RUN,test)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int foo() { return 0; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#[link(name = "test")]
2+
extern "C" {
3+
fn foo() -> i32;
4+
}
5+
6+
fn main() {
7+
unsafe {foo();}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// compile-flags: -Z branch-protection=leaf
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: incorrect value `leaf` for debugging option `branch-protection` - a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf` was expected
2+

0 commit comments

Comments
 (0)