Skip to content

Commit 8b6016a

Browse files
committed
Add -Zfunction-return={keep,thunk-extern} option
This is intended to be used for Linux kernel RETHUNK builds. With this commit (optionally backported to Rust 1.73.0), plus a patched Linux kernel to pass the flag, I get a RETHUNK build with Rust enabled that is `objtool`-warning-free and is able to boot in QEMU and load a sample Rust kernel module. Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent df66b8b commit 8b6016a

File tree

17 files changed

+207
-6
lines changed

17 files changed

+207
-6
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_codegen_ssa::traits::*;
44
use rustc_hir::def_id::DefId;
55
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
66
use rustc_middle::ty::{self, TyCtxt};
7-
use rustc_session::config::OptLevel;
7+
use rustc_session::config::{FunctionReturn, OptLevel};
88
use rustc_span::symbol::sym;
99
use rustc_target::spec::abi::Abi;
1010
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
@@ -118,6 +118,15 @@ pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attr
118118
Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
119119
}
120120

121+
fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
122+
let function_return_attr = match cx.sess().opts.unstable_opts.function_return {
123+
FunctionReturn::Keep => return None,
124+
FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern,
125+
};
126+
127+
Some(function_return_attr.create_attr(cx.llcx))
128+
}
129+
121130
/// Tell LLVM what instrument function to insert.
122131
#[inline]
123132
fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> {
@@ -333,6 +342,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
333342

334343
// FIXME: none of these functions interact with source level attributes.
335344
to_add.extend(frame_pointer_type_attr(cx));
345+
to_add.extend(function_return_attr(cx));
336346
to_add.extend(instrument_function_attr(cx));
337347
to_add.extend(nojumptables_attr(cx));
338348
to_add.extend(probestack_attr(cx));

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ pub enum AttributeKind {
200200
AllocatedPointer = 38,
201201
AllocAlign = 39,
202202
SanitizeSafeStack = 40,
203+
FnRetThunkExtern = 41,
203204
}
204205

205206
/// LLVMIntPredicate

compiler/rustc_interface/src/tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_data_structures::profiling::TimePassesFormat;
66
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
77
use rustc_session::config::rustc_optgroups;
88
use rustc_session::config::DebugInfo;
9+
use rustc_session::config::FunctionReturn;
910
use rustc_session::config::Input;
1011
use rustc_session::config::InstrumentXRay;
1112
use rustc_session::config::LinkSelfContained;
@@ -782,6 +783,7 @@ fn test_unstable_options_tracking_hash() {
782783
tracked!(flatten_format_args, false);
783784
tracked!(force_unstable_if_unmarked, true);
784785
tracked!(fuel, Some(("abc".to_string(), 99)));
786+
tracked!(function_return, FunctionReturn::ThunkExtern);
785787
tracked!(function_sections, Some(false));
786788
tracked!(human_readable_cgu_names, true);
787789
tracked!(incremental_ignore_spans, true);

compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ enum LLVMRustAttribute {
9494
AllocatedPointer = 38,
9595
AllocAlign = 39,
9696
SanitizeSafeStack = 40,
97+
FnRetThunkExtern = 41,
9798
};
9899

99100
typedef struct OpaqueRustString *RustStringRef;

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
283283
return Attribute::AllocAlign;
284284
case SanitizeSafeStack:
285285
return Attribute::SafeStack;
286+
case FnRetThunkExtern:
287+
return Attribute::FnRetThunkExtern;
286288
}
287289
report_fatal_error("bad AttributeKind");
288290
}

compiler/rustc_session/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it
2626
2727
session_file_write_fail = failed to write `{$path}` due to error `{$err}`
2828
29+
session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64
30+
31+
session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models
32+
2933
session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
3034
3135
session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target

compiler/rustc_session/src/config.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,10 +3213,10 @@ impl PpMode {
32133213
pub(crate) mod dep_tracking {
32143214
use super::{
32153215
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
3216-
ErrorOutputType, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
3217-
LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius,
3218-
RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
3219-
SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
3216+
ErrorOutputType, FunctionReturn, InstrumentCoverage, InstrumentXRay, LinkerPluginLto,
3217+
LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
3218+
Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm,
3219+
SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
32203220
};
32213221
use crate::lint;
32223222
use crate::options::WasiExecModel;
@@ -3322,6 +3322,7 @@ pub(crate) mod dep_tracking {
33223322
LanguageIdentifier,
33233323
TraitSolver,
33243324
Polonius,
3325+
FunctionReturn,
33253326
);
33263327

33273328
impl<T1, T2> DepTrackingHash for (T1, T2)
@@ -3492,3 +3493,14 @@ impl Polonius {
34923493
matches!(self, Polonius::Next)
34933494
}
34943495
}
3496+
3497+
/// The different settings that the `-Zfunction-return` flag can have.
3498+
#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3499+
pub enum FunctionReturn {
3500+
/// Keep the function return unmodified.
3501+
#[default]
3502+
Keep,
3503+
3504+
/// Replace returns with jumps to thunk, without emitting the thunk.
3505+
ThunkExtern,
3506+
}

compiler/rustc_session/src/errors.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,3 +436,11 @@ pub struct IncompatibleLinkerFlavor {
436436
pub flavor: &'static str,
437437
pub compatible_list: String,
438438
}
439+
440+
#[derive(Diagnostic)]
441+
#[diag(session_function_return_requires_x86_or_x86_64)]
442+
pub(crate) struct FunctionReturnRequiresX86OrX8664;
443+
444+
#[derive(Diagnostic)]
445+
#[diag(session_function_return_thunk_extern_requires_non_large_code_model)]
446+
pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel;

compiler/rustc_session/src/options.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ mod desc {
428428
"one of supported execution strategies (`same-thread`, or `cross-thread`)";
429429
pub const parse_dump_solver_proof_tree: &str = "one of: `always`, `on-request`, `on-error`";
430430
pub const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `unsplit-debuginfo`, `split-debuginfo`, `split-debuginfo-path`, `object`, `all`";
431+
pub const parse_function_return: &str = "`keep` or `thunk-extern`";
431432
}
432433

433434
mod parse {
@@ -1309,6 +1310,15 @@ mod parse {
13091310
};
13101311
true
13111312
}
1313+
1314+
pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool {
1315+
match v {
1316+
Some("keep") => *slot = FunctionReturn::Keep,
1317+
Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern,
1318+
_ => return false,
1319+
}
1320+
true
1321+
}
13121322
}
13131323

13141324
options! {
@@ -1555,6 +1565,8 @@ options! {
15551565
"force all crates to be `rustc_private` unstable (default: no)"),
15561566
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
15571567
"set the optimization fuel quota for a crate"),
1568+
function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED],
1569+
"replace returns with jumps to `__x86_return_thunk` (default: `keep`)"),
15581570
function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED],
15591571
"whether each function should go in its own section"),
15601572
future_incompat_test: bool = (false, parse_bool, [UNTRACKED],

compiler/rustc_session/src/session.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::code_stats::CodeStats;
22
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
33
use crate::config::{
4-
self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType,
4+
self, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName, OutputType,
55
RemapPathScopeComponents, SwitchWithOptPath,
66
};
77
use crate::config::{ErrorOutputType, Input};
@@ -1695,6 +1695,25 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
16951695
sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
16961696
}
16971697
}
1698+
1699+
if sess.opts.unstable_opts.function_return != FunctionReturn::default() {
1700+
if sess.target.arch != "x86" && sess.target.arch != "x86_64" {
1701+
sess.emit_err(errors::FunctionReturnRequiresX86OrX8664);
1702+
}
1703+
}
1704+
1705+
// This applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is kept as a
1706+
// `match` to force a change even if we only support `thunk-extern` like Clang.
1707+
match sess.opts.unstable_opts.function_return {
1708+
FunctionReturn::Keep => (),
1709+
FunctionReturn::ThunkExtern => {
1710+
// FIXME: In principle, the inherited base LLVM target code model could be large,
1711+
// but this only checks whether we were passed one explicitly (like Clang does).
1712+
if let Some(code_model) = sess.code_model() && code_model == CodeModel::Large {
1713+
sess.emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel);
1714+
}
1715+
}
1716+
}
16981717
}
16991718

17001719
/// Holds data on the current incremental compilation session, if there is one.

0 commit comments

Comments
 (0)