Skip to content

Commit 29e4ca6

Browse files
maurernebulark
authored andcommitted
Support #[patchable_function_entries]
See [RFC](https://github.com/maurer/rust-rfcs/blob/patchable-function-entry/text/0000-patchable-function-entry.md) (yet to be numbered) TODO before submission: * Needs an RFC * Improve error reporting for malformed attributes
1 parent 84956c5 commit 29e4ca6

File tree

9 files changed

+83
-4
lines changed

9 files changed

+83
-4
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use rustc_codegen_ssa::traits::*;
44
use rustc_hir::def_id::DefId;
5-
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
5+
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
66
use rustc_middle::ty::{self, TyCtxt};
77
use rustc_session::config::{FunctionReturn, OptLevel};
88
use rustc_span::symbol::sym;
@@ -56,9 +56,12 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll
5656
#[inline]
5757
fn patchable_function_entry_attrs<'ll>(
5858
cx: &CodegenCx<'ll, '_>,
59+
attr: Option<PatchableFunctionEntry>,
5960
) -> SmallVec<[&'ll Attribute; 2]> {
6061
let mut attrs = SmallVec::new();
61-
let patchable_spec = cx.tcx.sess.opts.unstable_opts.patchable_function_entry;
62+
let patchable_spec = attr.unwrap_or_else(|| {
63+
PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry)
64+
});
6265
let entry = patchable_spec.entry();
6366
let prefix = patchable_spec.prefix();
6467
if entry > 0 {
@@ -445,7 +448,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
445448
llvm::set_alignment(llfn, align);
446449
}
447450
to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
448-
to_add.extend(patchable_function_entry_attrs(cx));
451+
to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry));
449452

450453
// Always annotate functions with the target-cpu they are compiled for.
451454
// Without this, ThinLTO won't inline Rust functions into Clang generated

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use rustc_hir as hir;
55
use rustc_hir::def::DefKind;
66
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
77
use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
8-
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
8+
use rustc_middle::middle::codegen_fn_attrs::{
9+
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
10+
};
911
use rustc_middle::mir::mono::Linkage;
1012
use rustc_middle::query::Providers;
1113
use rustc_middle::ty::{self as ty, TyCtxt};
@@ -453,6 +455,28 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
453455
None
454456
};
455457
}
458+
sym::patchable_function_entry => {
459+
codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| {
460+
let mut prefix = 0;
461+
let mut entry = 0;
462+
for item in l {
463+
if let Some((sym, lit)) = item.name_value_literal() {
464+
let val = match lit.kind {
465+
// FIXME emit error if too many nops requested
466+
rustc_ast::LitKind::Int(i, _) => i as u8,
467+
_ => continue,
468+
};
469+
match sym {
470+
sym::prefix => prefix = val,
471+
sym::entry => entry = val,
472+
// FIXME possibly emit error here?
473+
_ => continue,
474+
}
475+
}
476+
}
477+
Some(PatchableFunctionEntry::from_prefix_and_entry(prefix, entry))
478+
})
479+
}
456480
_ => {}
457481
}
458482
}

compiler/rustc_feature/src/builtin_attrs.rs

+7
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
533533
EncodeCrossCrate::No, coroutines, experimental!(coroutines)
534534
),
535535

536+
// FIXME RFC
537+
// `#[patchable_function_entry(prefix(n), entry(n))]`
538+
gated!(
539+
patchable_function_entry, Normal, template!(List: "prefix(n), entry(n)"), ErrorPreceding,
540+
experimental!(patchable_function_entry)
541+
),
542+
536543
// ==========================================================================
537544
// Internal attributes: Stability, deprecation, and unsafe:
538545
// ==========================================================================

compiler/rustc_feature/src/unstable.rs

+3
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,9 @@ declare_features! (
561561
(unstable, offset_of_nested, "1.77.0", Some(120140)),
562562
/// Allows using `#[optimize(X)]`.
563563
(unstable, optimize_attribute, "1.34.0", Some(54882)),
564+
/// Allows specifying nop padding on functions for dynamic patching.
565+
// FIXME this needs an RFC #
566+
(unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(9999)),
564567
/// Allows postfix match `expr.match { ... }`
565568
(unstable, postfix_match, "1.79.0", Some(121618)),
566569
/// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args.

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ pub struct CodegenFnAttrs {
4545
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
4646
/// aligned to.
4747
pub alignment: Option<Align>,
48+
/// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
49+
/// the function entry.
50+
pub patchable_function_entry: Option<PatchableFunctionEntry>,
4851
}
4952

5053
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -147,6 +150,7 @@ impl CodegenFnAttrs {
147150
no_sanitize: SanitizerSet::empty(),
148151
instruction_set: None,
149152
alignment: None,
153+
patchable_function_entry: None,
150154
}
151155
}
152156

compiler/rustc_span/src/symbol.rs

+3
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ symbols! {
754754
enable,
755755
encode,
756756
end,
757+
entry,
757758
enumerate_method,
758759
env,
759760
env_CFG_RELEASE: env!("CFG_RELEASE"),
@@ -1360,6 +1361,7 @@ symbols! {
13601361
passes,
13611362
pat,
13621363
pat_param,
1364+
patchable_function_entry,
13631365
path,
13641366
pattern_complexity,
13651367
pattern_parentheses,
@@ -1397,6 +1399,7 @@ symbols! {
13971399
prefetch_read_instruction,
13981400
prefetch_write_data,
13991401
prefetch_write_instruction,
1402+
prefix,
14001403
preg,
14011404
prelude,
14021405
prelude_import,
+20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1+
#![feature(patchable_function_entry)]
12
// compile-flags: -Z patchable-function-entry=15,10
23

34
#![crate_type = "lib"]
45

6+
// This should have the default, as set by the compile flags
57
#[no_mangle]
68
pub fn foo() {}
9+
10+
// The attribute should override the compile flags
11+
#[no_mangle]
12+
#[patchable_function_entry(prefix(1), entry(2))]
13+
pub fn bar() {}
14+
15+
// If we override an attribute to 0 or unset, the attribute should go away
16+
#[no_mangle]
17+
#[patchable_function_entry(entry(0))]
18+
pub fn baz() {}
19+
720
// CHECK: @foo() unnamed_addr #0
21+
// CHECK: @bar() unnamed_addr #1
22+
// CHECK: @baz() unnamed_addr #2
23+
824
// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} }
25+
// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
26+
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} }
27+
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
28+
// CHECK: attributes #2 = { {{.*}} }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#[patchable_function_entry(entry(1), prefix(1))]
2+
//~^ ERROR: the `#[patchable_function_entry]` attribute is an experimental feature
3+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: the `#[patchable_function_entry]` attribute is an experimental feature
2+
--> $DIR/feature-gate-patchable-function-entry.rs:1:1
3+
|
4+
LL | #[patchable_function_entry(entry(1), prefix(1))]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #9999 <https://github.com/rust-lang/rust/issues/9999> for more information
8+
= help: add `#![feature(patchable_function_entry)]` to the crate attributes to enable
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)