Skip to content

Commit b51b1b6

Browse files
committed
Auto merge of #157445 - pmur:murp/extend-patchable, r=<try>
Allow section override when using patchable-function-entries try-job: dist-x86_64-msvc
2 parents 0966944 + c340e8a commit b51b1b6

18 files changed

Lines changed: 257 additions & 74 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use rustc_span::edition::Edition::Edition2024;
88
use super::prelude::*;
99
use crate::attributes::AttributeSafety;
1010
use crate::session_diagnostics::{
11-
EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
12-
NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
13-
SanitizeInvalidStatic, TargetFeatureOnLangItem,
11+
EmptyExportName, EmptySection, NakedFunctionIncompatibleAttribute, NullOnExport,
12+
NullOnObjcClass, NullOnObjcSelector, NullOnSection, ObjcClassExpectedStringLiteral,
13+
ObjcSelectorExpectedStringLiteral, SanitizeInvalidStatic, TargetFeatureOnLangItem,
1414
};
1515
use crate::target_checking::Policy::AllowSilent;
1616

@@ -795,82 +795,94 @@ pub(crate) struct PatchableFunctionEntryParser;
795795
impl SingleAttributeParser for PatchableFunctionEntryParser {
796796
const PATH: &[Symbol] = &[sym::patchable_function_entry];
797797
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
798-
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
798+
const TEMPLATE: AttributeTemplate =
799+
template!(List: &["prefix_nops = m, entry_nops = n, section = \"section\""]);
799800
const STABILITY: AttributeStability = unstable!(patchable_function_entry);
800801

801802
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
802803
let meta_item_list = cx.expect_list(args, cx.attr_span)?;
803804

804805
let mut prefix = None;
805806
let mut entry = None;
807+
let mut section = None;
806808

807809
if meta_item_list.len() == 0 {
808810
cx.adcx().expected_at_least_one_argument(meta_item_list.span);
809811
return None;
810812
}
811813

812-
let mut errored = false;
813-
814814
for item in meta_item_list.mixed() {
815815
let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
816-
continue;
816+
return None;
817817
};
818818

819819
let attrib_to_write = match ident.name {
820820
sym::prefix_nops => {
821821
// Duplicate prefixes are not allowed
822822
if prefix.is_some() {
823-
errored = true;
824823
cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
825-
continue;
824+
return None;
826825
}
827826
&mut prefix
828827
}
829828
sym::entry_nops => {
830829
// Duplicate entries are not allowed
831830
if entry.is_some() {
832-
errored = true;
833831
cx.adcx().duplicate_key(ident.span, sym::entry_nops);
834-
continue;
832+
return None;
835833
}
836834
&mut entry
837835
}
836+
sym::section => {
837+
// Duplicate entries are not allowed
838+
if section.is_some() {
839+
cx.adcx().duplicate_key(ident.span, sym::section);
840+
return None;
841+
}
842+
// Only a string type value is allowed.
843+
let Some(value_str) = value.value_as_str() else {
844+
cx.adcx().expect_string_literal(value);
845+
return None;
846+
};
847+
// The section name does not allow null characters.
848+
if value_str.as_str().contains('\0') {
849+
cx.emit_err(NullOnSection { span: value.value_span });
850+
}
851+
// The section name is not allowed to be empty, LLVM does
852+
// not allow them.
853+
if value_str.is_empty() {
854+
cx.emit_err(EmptySection { span: value.value_span });
855+
}
856+
section = Some(value_str);
857+
// Integer parsing is not needed, process next item.
858+
continue;
859+
}
838860
_ => {
839-
errored = true;
840861
cx.adcx().expected_specific_argument(
841862
ident.span,
842863
&[sym::prefix_nops, sym::entry_nops],
843864
);
844-
continue;
865+
return None;
845866
}
846867
};
847868

848869
let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else {
849-
errored = true;
850870
cx.adcx().expected_integer_literal(value.value_span);
851-
continue;
871+
return None;
852872
};
853873

854874
let Ok(val) = val.get().try_into() else {
855-
errored = true;
856875
cx.adcx().expected_integer_literal_in_range(
857876
value.value_span,
858877
u8::MIN as isize,
859878
u8::MAX as isize,
860879
);
861-
continue;
880+
return None;
862881
};
863882

864883
*attrib_to_write = Some(val);
865884
}
866885

867-
if errored {
868-
None
869-
} else {
870-
Some(AttributeKind::PatchableFunctionEntry {
871-
prefix: prefix.unwrap_or(0),
872-
entry: entry.unwrap_or(0),
873-
})
874-
}
886+
Some(AttributeKind::PatchableFunctionEntry { prefix, entry, section })
875887
}
876888
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,13 @@ pub(crate) struct EmptyExportName {
292292
pub span: Span,
293293
}
294294

295+
#[derive(Diagnostic)]
296+
#[diag("`section` may not be empty")]
297+
pub(crate) struct EmptySection {
298+
#[primary_span]
299+
pub span: Span,
300+
}
301+
295302
#[derive(Diagnostic)]
296303
#[diag("`export_name` may not contain null characters", code = E0648)]
297304
pub(crate) struct NullOnExport {
@@ -327,6 +334,13 @@ pub(crate) struct NullOnObjcSelector {
327334
pub span: Span,
328335
}
329336

337+
#[derive(Diagnostic)]
338+
#[diag("`section` may not contain null characters", code = E0648)]
339+
pub(crate) struct NullOnSection {
340+
#[primary_span]
341+
pub span: Span,
342+
}
343+
330344
#[derive(Diagnostic)]
331345
#[diag("`objc::class!` expected a string literal")]
332346
pub(crate) struct ObjcClassExpectedStringLiteral {

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,26 @@ fn patchable_function_entry_attrs<'ll>(
8686
attr: Option<PatchableFunctionEntry>,
8787
) -> SmallVec<[&'ll Attribute; 2]> {
8888
let mut attrs = SmallVec::new();
89-
let patchable_spec = attr.unwrap_or_else(|| {
90-
PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry)
91-
});
92-
let entry = patchable_spec.entry();
93-
let prefix = patchable_spec.prefix();
89+
90+
let mut entry = sess.opts.unstable_opts.patchable_function_entry.entry();
91+
let mut prefix = sess.opts.unstable_opts.patchable_function_entry.prefix();
92+
let mut section = sess.opts.unstable_opts.patchable_function_entry.section();
93+
let section_sym;
94+
95+
// Apply attribute specified overrides, if any.
96+
if let Some(patchable_spec) = attr {
97+
if let Some(sym) = patchable_spec.section() {
98+
section_sym = sym;
99+
section = Some(section_sym.as_str());
100+
}
101+
// Override the nop counts if either is present. If only one is present, the
102+
// other count is implied to be 0.
103+
if patchable_spec.entry().is_some() || patchable_spec.prefix().is_some() {
104+
entry = patchable_spec.entry().unwrap_or(0);
105+
prefix = patchable_spec.prefix().unwrap_or(0);
106+
}
107+
}
108+
94109
if entry > 0 {
95110
attrs.push(llvm::CreateAttrStringValue(
96111
cx.llcx,
@@ -105,6 +120,13 @@ fn patchable_function_entry_attrs<'ll>(
105120
&format!("{}", prefix),
106121
));
107122
}
123+
if let Some(section) = section {
124+
attrs.push(llvm::CreateAttrStringValue(
125+
cx.llcx,
126+
"patchable-function-entry-section",
127+
section,
128+
));
129+
}
108130
attrs
109131
}
110132

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
1414
use rustc_data_structures::fx::FxHashMap;
1515
use rustc_data_structures::small_c_str::SmallCStr;
1616
use rustc_hir::def_id::DefId;
17-
use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry;
1817
use rustc_middle::mono::CodegenUnit;
1918
use rustc_middle::ty::layout::{
2019
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
@@ -343,14 +342,13 @@ pub(crate) unsafe fn create_module<'ll>(
343342

344343
// Add "kcfi-offset" module flag with -Z patchable-function-entry (See
345344
// https://reviews.llvm.org/D141172).
346-
let pfe =
347-
PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry);
348-
if pfe.prefix() > 0 {
345+
let patchable_prefix_nops = sess.opts.unstable_opts.patchable_function_entry.prefix();
346+
if patchable_prefix_nops > 0 {
349347
llvm::add_module_flag_u32(
350348
llmod,
351349
llvm::ModuleFlagMergeBehavior::Override,
352350
"kcfi-offset",
353-
pfe.prefix().into(),
351+
patchable_prefix_nops.into(),
354352
);
355353
}
356354

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,11 @@ fn process_builtin_attrs(
290290
AttributeKind::RustcOffloadKernel => {
291291
codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL
292292
}
293-
AttributeKind::PatchableFunctionEntry { prefix, entry } => {
293+
AttributeKind::PatchableFunctionEntry { prefix, entry, section } => {
294294
codegen_fn_attrs.patchable_function_entry =
295-
Some(PatchableFunctionEntry::from_prefix_and_entry(*prefix, *entry));
295+
Some(PatchableFunctionEntry::from_prefix_entry_and_section(
296+
*prefix, *entry, *section,
297+
));
296298
}
297299
AttributeKind::InstrumentFn(instrument_fn) => {
298300
codegen_fn_attrs.instrument_fn = match instrument_fn {

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,8 +1271,9 @@ pub enum AttributeKind {
12711271

12721272
/// Represents `#[patchable_function_entry]`
12731273
PatchableFunctionEntry {
1274-
prefix: u8,
1275-
entry: u8,
1274+
prefix: Option<u8>,
1275+
entry: Option<u8>,
1276+
section: Option<Symbol>,
12761277
},
12771278

12781279
/// Represents `#[path]`

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,7 @@ fn test_unstable_options_tracking_hash() {
866866
tracked!(panic_in_drop, PanicStrategy::Abort);
867867
tracked!(
868868
patchable_function_entry,
869-
PatchableFunctionEntry::from_total_and_prefix_nops(10, 5)
869+
PatchableFunctionEntry::from_parts(10, 5, None)
870870
.expect("total must be greater than or equal to prefix")
871871
);
872872
tracked!(plt, Some(true));

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ pub struct CodegenFnAttrs {
114114
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
115115
pub alignment: Option<Align>,
116116
/// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
117-
/// the function entry.
117+
/// the function entry, or override default section to record entry location.
118118
pub patchable_function_entry: Option<PatchableFunctionEntry>,
119119
/// The `#[rustc_objc_class = "..."]` attribute.
120120
pub objc_class: Option<Symbol>,
@@ -162,24 +162,33 @@ pub struct TargetFeature {
162162
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, StableHash)]
163163
pub struct PatchableFunctionEntry {
164164
/// Nops to prepend to the function
165-
prefix: u8,
165+
prefix: Option<u8>,
166166
/// Nops after entry, but before body
167-
entry: u8,
167+
entry: Option<u8>,
168+
/// Optional, specific section to record entry location in
169+
section: Option<Symbol>,
168170
}
169171

170172
impl PatchableFunctionEntry {
171-
pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self {
172-
Self { prefix: config.prefix(), entry: config.entry() }
173+
pub fn from_prefix_entry_and_section(
174+
prefix: Option<u8>,
175+
entry: Option<u8>,
176+
section: Option<Symbol>,
177+
) -> Self {
178+
Self { prefix, entry, section }
173179
}
174180
pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self {
175-
Self { prefix, entry }
181+
Self { prefix: Some(prefix), entry: Some(entry), section: None }
176182
}
177-
pub fn prefix(&self) -> u8 {
183+
pub fn prefix(&self) -> Option<u8> {
178184
self.prefix
179185
}
180-
pub fn entry(&self) -> u8 {
186+
pub fn entry(&self) -> Option<u8> {
181187
self.entry
182188
}
189+
pub fn section(&self) -> Option<Symbol> {
190+
self.section
191+
}
183192
}
184193

185194
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, StableHash)]

compiler/rustc_session/src/config.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,23 +3342,29 @@ impl DumpMonoStatsFormat {
33423342

33433343
/// `-Z patchable-function-entry` representation - how many nops to put before and after function
33443344
/// entry.
3345-
#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3345+
#[derive(Clone, PartialEq, Hash, Debug, Default)]
33463346
pub struct PatchableFunctionEntry {
33473347
/// Nops before the entry
33483348
prefix: u8,
33493349
/// Nops after the entry
33503350
entry: u8,
3351+
/// An optional section name to record the entry location
3352+
section: Option<String>,
33513353
}
33523354

33533355
impl PatchableFunctionEntry {
3354-
pub fn from_total_and_prefix_nops(
3356+
pub fn from_parts(
33553357
total_nops: u8,
33563358
prefix_nops: u8,
3359+
section: Option<String>,
33573360
) -> Option<PatchableFunctionEntry> {
33583361
if total_nops < prefix_nops {
33593362
None
3363+
// Section name cannot contain null characters.
3364+
} else if section.as_ref().map(|x| x.contains('\0') || x.is_empty()).unwrap_or(false) {
3365+
None
33603366
} else {
3361-
Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops })
3367+
Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops, section })
33623368
}
33633369
}
33643370
pub fn prefix(&self) -> u8 {
@@ -3367,6 +3373,9 @@ impl PatchableFunctionEntry {
33673373
pub fn entry(&self) -> u8 {
33683374
self.entry
33693375
}
3376+
pub fn section(&self) -> Option<&str> {
3377+
self.section.as_ref().map(|x| x.as_str())
3378+
}
33703379
}
33713380

33723381
/// `-Zpolonius` values, enabling the borrow checker polonius analysis, and which version: legacy,

compiler/rustc_session/src/options.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ mod desc {
784784
pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`";
785785
pub(crate) const parse_panic_strategy: &str = "either `unwind`, `abort`, or `immediate-abort`";
786786
pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
787-
pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)";
787+
pub(crate) const parse_patchable_function_entry: &str = "a comma separated list of (prefix_nops,total_nops,section_name), (prefix_nops,total_nops), or (total_nops). Where prefix_nops <= total_nops where 0 < total_nops <= 255 and prefix_nops <= total_nops";
788788
pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy;
789789
pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
790790
pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `kernel-hwaddress`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'";
@@ -1206,20 +1206,24 @@ pub mod parse {
12061206
) -> bool {
12071207
let mut total_nops = 0;
12081208
let mut prefix_nops = 0;
1209+
let mut section = None;
12091210

12101211
if !parse_number(&mut total_nops, v) {
1211-
let parts = v.and_then(|v| v.split_once(',')).unzip();
1212-
if !parse_number(&mut total_nops, parts.0) {
1212+
let parts: Vec<_> = v.unwrap_or("").split(',').collect();
1213+
if parts.len() < 2 || parts.len() > 3 {
12131214
return false;
12141215
}
1215-
if !parse_number(&mut prefix_nops, parts.1) {
1216+
1217+
if !parse_number(&mut total_nops, Some(parts[0])) {
1218+
return false;
1219+
}
1220+
if !parse_number(&mut prefix_nops, Some(parts[1])) {
12161221
return false;
12171222
}
1223+
section = parts.get(2).map(|x| x.to_string());
12181224
}
12191225

1220-
if let Some(pfe) =
1221-
PatchableFunctionEntry::from_total_and_prefix_nops(total_nops, prefix_nops)
1222-
{
1226+
if let Some(pfe) = PatchableFunctionEntry::from_parts(total_nops, prefix_nops, section) {
12231227
*slot = pfe;
12241228
return true;
12251229
}

0 commit comments

Comments
 (0)