Skip to content

Commit 0faa8ac

Browse files
committed
New signature of get_fn_addr, teach Rust how to sign fn pointers
Allow PAC metadata to be passed to `get_fn_addr` and related API changes.
1 parent 10a508b commit 0faa8ac

13 files changed

Lines changed: 193 additions & 41 deletions

File tree

compiler/rustc_codegen_gcc/src/common.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use gccjit::{LValue, RValue, ToRValue, Type};
22
use rustc_abi::Primitive::Pointer;
33
use rustc_abi::{self as abi, HasDataLayout};
44
use rustc_codegen_ssa::traits::{
5-
BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
5+
BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, PacMetadata,
6+
StaticCodegenMethods,
67
};
78
use rustc_middle::mir::Mutability;
89
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
@@ -225,7 +226,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
225226
None
226227
}
227228

228-
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
229+
fn scalar_to_backend_with_pac(
230+
&self,
231+
cv: Scalar,
232+
layout: abi::Scalar,
233+
ty: Type<'gcc>,
234+
_pac: Option<PacMetadata>,
235+
) -> RValue<'gcc> {
229236
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
230237
match cv {
231238
Scalar::Int(int) => {
@@ -274,7 +281,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
274281
}
275282
value
276283
}
277-
GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
284+
GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, None),
278285
GlobalAlloc::VTable(ty, dyn_ty) => {
279286
let alloc = self
280287
.tcx

compiler/rustc_codegen_gcc/src/context.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use gccjit::{
77
use rustc_abi::{Align, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
88
use rustc_codegen_ssa::base::wants_msvc_seh;
99
use rustc_codegen_ssa::errors as ssa_errors;
10-
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods};
10+
use rustc_codegen_ssa::traits::{
11+
BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods, PacMetadata,
12+
};
1113
use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
1214
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1315
use rustc_middle::mir::interpret::Allocation;
@@ -403,7 +405,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
403405
get_fn(self, instance)
404406
}
405407

406-
fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
408+
fn get_fn_addr(&self, instance: Instance<'tcx>, _pac: Option<PacMetadata>) -> RValue<'gcc> {
407409
let func_name = self.tcx.symbol_name(instance).name;
408410

409411
let func = if let Some(variable) = self.get_declared_value(func_name) {

compiler/rustc_codegen_llvm/src/base.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ use rustc_middle::mir::mono::Visibility;
2525
use rustc_middle::ty::TyCtxt;
2626
use rustc_session::config::{DebugInfo, Offload};
2727
use rustc_span::Symbol;
28-
use rustc_target::spec::SanitizerSet;
28+
use rustc_target::spec::{Env, SanitizerSet};
2929

3030
use super::ModuleLlvm;
3131
use crate::attributes;
3232
use crate::builder::Builder;
3333
use crate::builder::gpu_offload::OffloadGlobals;
34+
use crate::common::pauth_fn_attrs;
3435
use crate::context::CodegenCx;
3536
use crate::llvm::{self, Value};
3637

compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,81 @@ use std::borrow::Borrow;
44

55
use libc::{c_char, c_uint};
66
use rustc_abi::Primitive::Pointer;
7-
use rustc_abi::{self as abi, HasDataLayout as _};
7+
use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _};
88
use rustc_ast::Mutability;
99
use rustc_codegen_ssa::common::TypeKind;
1010
use rustc_codegen_ssa::traits::*;
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1212
use rustc_hashes::Hash128;
13+
use rustc_hir::def::DefKind;
1314
use rustc_hir::def_id::DefId;
1415
use rustc_middle::bug;
1516
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
16-
use rustc_middle::ty::TyCtxt;
17+
use rustc_middle::ty::{Instance, TyCtxt};
1718
use rustc_session::cstore::DllImport;
19+
use rustc_target::spec::Env;
1820
use tracing::debug;
1921

20-
use crate::consts::const_alloc_to_llvm;
22+
use crate::consts::{IsInitOrFini, IsStatic, const_alloc_to_llvm};
2123
pub(crate) use crate::context::CodegenCx;
2224
use crate::context::{GenericCx, SCx};
23-
use crate::llvm::{self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value};
25+
use crate::llvm::{
26+
self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value, const_ptr_auth,
27+
};
28+
29+
#[inline]
30+
pub(crate) fn pauth_fn_attrs() -> &'static [&'static str] {
31+
// FIXME(jchlanda) This is not an exhaustive list of all `pauthtest`-related attributes, but
32+
// only those currently supported. The list is expected to grow as additional functionality is
33+
// implemented, particularly for C++ interoperability.
34+
&[
35+
"aarch64-jump-table-hardening",
36+
"ptrauth-indirect-gotos",
37+
"ptrauth-calls",
38+
"ptrauth-returns",
39+
"ptrauth-auth-traps",
40+
]
41+
}
42+
43+
pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>(
44+
cx: &CodegenCx<'ll, '_>,
45+
instance: Instance<'tcx>,
46+
llfn: &'ll llvm::Value,
47+
pac: PacMetadata,
48+
) -> &'ll llvm::Value {
49+
if cx.sess().target.env != Env::Pauthtest {
50+
return llfn;
51+
}
52+
53+
// Only free functions or methods
54+
let def_id = instance.def_id();
55+
if !matches!(cx.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
56+
return llfn;
57+
}
58+
// Only C ABI
59+
let abi = cx.tcx.fn_sig(def_id).skip_binder().abi();
60+
if !matches!(abi, ExternAbi::C { .. }) {
61+
return llfn;
62+
}
63+
// Ignore LLVM intrinsics
64+
if llvm::get_value_name(llfn).starts_with(b"llvm.") {
65+
return llfn;
66+
}
67+
if Some(def_id) == cx.tcx.lang_items().eh_personality() {
68+
return llfn;
69+
}
70+
71+
let addr_diversity = match pac.addr_diversity {
72+
AddressDiversity::None => None,
73+
AddressDiversity::Real => Some(llfn),
74+
AddressDiversity::Synthetic(val) => {
75+
let llval = cx.const_u64(val);
76+
let llty = cx.val_ty(llfn);
77+
Some(unsafe { llvm::LLVMConstIntToPtr(llval, llty) })
78+
}
79+
};
80+
const_ptr_auth(llfn, pac.key, pac.disc, addr_diversity)
81+
}
2482

2583
/*
2684
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
@@ -264,7 +322,13 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
264322
})
265323
}
266324

267-
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
325+
fn scalar_to_backend_with_pac(
326+
&self,
327+
cv: Scalar,
328+
layout: abi::Scalar,
329+
llty: &'ll Type,
330+
pac: Option<PacMetadata>,
331+
) -> &'ll Value {
268332
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
269333
match cv {
270334
Scalar::Int(int) => {
@@ -293,8 +357,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
293357
self.const_bitcast(llval, llty)
294358
};
295359
} else {
296-
let init =
297-
const_alloc_to_llvm(self, alloc.inner(), /*static*/ false);
360+
let init = const_alloc_to_llvm(
361+
self,
362+
alloc.inner(),
363+
IsStatic::No,
364+
IsInitOrFini::No,
365+
);
298366
let alloc = alloc.inner();
299367
let value = match alloc.mutability {
300368
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
@@ -315,7 +383,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
315383
value
316384
}
317385
}
318-
GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
386+
GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, pac),
319387
GlobalAlloc::VTable(ty, dyn_ty) => {
320388
let alloc = self
321389
.tcx
@@ -326,7 +394,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
326394
}),
327395
)))
328396
.unwrap_memory();
329-
let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false);
397+
let init = const_alloc_to_llvm(
398+
self,
399+
alloc.inner(),
400+
IsStatic::No,
401+
IsInitOrFini::No,
402+
);
330403
self.static_addr_of_impl(init, alloc.inner().align, None)
331404
}
332405
GlobalAlloc::Static(def_id) => {

compiler/rustc_codegen_llvm/src/consts.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::ops::Range;
22

3-
use rustc_abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
3+
use rustc_abi::{Align, ExternAbi, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
44
use rustc_codegen_ssa::common;
55
use rustc_codegen_ssa::traits::*;
66
use rustc_hir::LangItem;
@@ -17,19 +17,30 @@ use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
1717
use rustc_middle::ty::{self, Instance};
1818
use rustc_middle::{bug, span_bug};
1919
use rustc_span::Symbol;
20-
use rustc_target::spec::Arch;
20+
use rustc_target::spec::{Arch, Env};
2121
use tracing::{debug, instrument, trace};
2222

2323
use crate::common::CodegenCx;
2424
use crate::errors::SymbolAlreadyDefined;
25-
use crate::llvm::{self, Type, Value};
25+
use crate::llvm::{self, Type, Value, const_ptr_auth};
2626
use crate::type_of::LayoutLlvmExt;
2727
use crate::{base, debuginfo};
2828

29+
/// Indicates whether a value originates from a `static`.
30+
pub(crate) enum IsStatic {
31+
Yes,
32+
No,
33+
}
34+
/// Indicates whether a symbol is part of `.init_array` or `.fini_array`.
35+
pub(crate) enum IsInitOrFini {
36+
Yes,
37+
No,
38+
}
2939
pub(crate) fn const_alloc_to_llvm<'ll>(
3040
cx: &CodegenCx<'ll, '_>,
3141
alloc: &Allocation,
32-
is_static: bool,
42+
is_static: IsStatic,
43+
is_init_fini: IsInitOrFini,
3344
) -> &'ll Value {
3445
// We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or
3546
// integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be
@@ -775,7 +786,7 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> {
775786
fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value {
776787
// FIXME: should we cache `const_alloc_to_llvm` to avoid repeating this for the
777788
// same `ConstAllocation`?
778-
let cv = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false);
789+
let cv = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No);
779790

780791
let gv = self.static_addr_of_impl(cv, alloc.inner().align, kind);
781792
// static_addr_of_impl returns the bare global variable, which might not be in the default

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -832,8 +832,12 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
832832
get_fn(self, instance)
833833
}
834834

835-
fn get_fn_addr(&self, instance: Instance<'tcx>) -> &'ll Value {
836-
get_fn(self, instance)
835+
fn get_fn_addr(&self, instance: Instance<'tcx>, pac: Option<PacMetadata>) -> &'ll Value {
836+
let llfn = get_fn(self, instance);
837+
match pac {
838+
Some(pac) => common::maybe_sign_fn_ptr(self, instance, llfn, pac),
839+
None => llfn,
840+
}
837841
}
838842

839843
fn eh_personality(&self) -> &'ll Value {
@@ -875,13 +879,16 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
875879

876880
let tcx = self.tcx;
877881
let llfn = match tcx.lang_items().eh_personality() {
878-
Some(def_id) if name.is_none() => self.get_fn_addr(ty::Instance::expect_resolve(
879-
tcx,
880-
self.typing_env(),
881-
def_id,
882-
ty::List::empty(),
883-
DUMMY_SP,
884-
)),
882+
Some(def_id) if name.is_none() => self.get_fn_addr(
883+
ty::Instance::expect_resolve(
884+
tcx,
885+
self.typing_env(),
886+
def_id,
887+
ty::List::empty(),
888+
DUMMY_SP,
889+
),
890+
Some(PacMetadata::default()),
891+
),
885892
_ => {
886893
let name = name.unwrap_or("rust_eh_personality");
887894
if let Some(llfn) = self.get_declared_value(name) {

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
485485
return None;
486486
}
487487

488-
let main_llfn = cx.get_fn_addr(instance);
488+
let main_llfn = cx.get_fn_addr(instance, Some(PacMetadata::default()));
489489

490490
let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
491491
return Some(entry_fn);
@@ -545,7 +545,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
545545
cx.tcx().mk_args(&[main_ret_ty.into()]),
546546
DUMMY_SP,
547547
);
548-
let start_fn = cx.get_fn_addr(start_instance);
548+
let start_fn = cx.get_fn_addr(start_instance, Some(PacMetadata::default()));
549549

550550
let i8_ty = cx.type_i8();
551551
let arg_sigpipe = bx.const_u8(sigpipe);

compiler/rustc_codegen_ssa/src/common.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,11 @@ pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
117117
let tcx = bx.tcx();
118118
let def_id = tcx.require_lang_item(li, span);
119119
let instance = ty::Instance::mono(tcx, def_id);
120-
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
120+
(
121+
bx.fn_abi_of_instance(instance, ty::List::empty()),
122+
bx.get_fn_addr(instance, Some(PacMetadata::default())),
123+
instance,
124+
)
121125
}
122126

123127
pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
657657
}
658658
_ => (
659659
false,
660-
bx.get_fn_addr(drop_fn),
660+
bx.get_fn_addr(drop_fn, Some(PacMetadata::default())),
661661
bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
662662
drop_fn,
663663
),
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10321032
)
10331033
.unwrap();
10341034

1035-
(None, Some(bx.get_fn_addr(instance)))
1035+
(None, Some(bx.get_fn_addr(instance, Some(PacMetadata::default()))))
10361036
}
10371037
_ => (Some(instance), None),
10381038
}
@@ -1338,7 +1338,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13381338
}
13391339

13401340
let fn_ptr = match (instance, llfn) {
1341-
(Some(instance), None) => bx.get_fn_addr(instance),
1341+
(Some(instance), None) => bx.get_fn_addr(instance, Some(PacMetadata::default())),
13421342
(_, Some(llfn)) => llfn,
13431343
_ => span_bug!(fn_span, "no instance or llfn for call"),
13441344
};

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
415415
args,
416416
)
417417
.unwrap();
418-
OperandValue::Immediate(bx.get_fn_addr(instance))
418+
OperandValue::Immediate(bx.get_fn_addr(instance,
419+
Some(PacMetadata::default()),
420+
))
419421
}
420422
_ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
421423
}
@@ -429,7 +431,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
429431
args,
430432
ty::ClosureKind::FnOnce,
431433
);
432-
OperandValue::Immediate(bx.cx().get_fn_addr(instance))
434+
OperandValue::Immediate(bx.cx().get_fn_addr(instance,
435+
Some(PacMetadata::default()),
436+
))
433437
}
434438
_ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
435439
}
@@ -628,7 +632,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
628632
def: ty::InstanceKind::ThreadLocalShim(def_id),
629633
args: ty::GenericArgs::empty(),
630634
};
631-
let fn_ptr = bx.get_fn_addr(instance);
635+
let fn_ptr = bx.get_fn_addr(instance, Some(PacMetadata::default()));
632636
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
633637
let fn_ty = bx.fn_decl_backend_type(fn_abi);
634638
let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() {

0 commit comments

Comments
 (0)