diff options
| author | bors <bors@rust-lang.org> | 2023-11-30 22:10:30 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-11-30 22:10:30 +0000 |
| commit | f45631b10f2199a7ef344a936af9eb60342c16ee (patch) | |
| tree | db7948a73b1bd350c06116e79d4168749dc3e41a /compiler | |
| parent | 87e1447aadaa2899ff6ccabe1fa669eb50fb60a1 (diff) | |
| parent | 2d476222e8458aa873e6760aac189b5e9d0a9930 (diff) | |
| download | rust-f45631b10f2199a7ef344a936af9eb60342c16ee.tar.gz rust-f45631b10f2199a7ef344a936af9eb60342c16ee.zip | |
Auto merge of #116892 - ojeda:rethunk, r=wesleywiser
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.
Issue: https://github.com/rust-lang/rust/issues/116853.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/attributes.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/tests.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h | 1 | ||||
| -rw-r--r-- | compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 | ||||
| -rw-r--r-- | compiler/rustc_session/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_session/src/config.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_session/src/errors.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_session/src/options.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_session/src/session.rs | 24 |
10 files changed, 84 insertions, 10 deletions
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 92ae59ad352..481741bb127 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -4,7 +4,7 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::OptLevel; +use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; 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 Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value)) } +fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { + let function_return_attr = match cx.sess().opts.unstable_opts.function_return { + FunctionReturn::Keep => return None, + FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern, + }; + + Some(function_return_attr.create_attr(cx.llcx)) +} + /// Tell LLVM what instrument function to insert. #[inline] fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> { @@ -331,8 +340,9 @@ pub fn from_fn_attrs<'ll, 'tcx>( to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile")); } - // FIXME: none of these three functions interact with source level attributes. + // FIXME: none of these functions interact with source level attributes. to_add.extend(frame_pointer_type_attr(cx)); + to_add.extend(function_return_attr(cx)); to_add.extend(instrument_function_attr(cx)); to_add.extend(nojumptables_attr(cx)); to_add.extend(probestack_attr(cx)); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index df4cd8ea0bd..d701b20e953 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -200,6 +200,7 @@ pub enum AttributeKind { AllocatedPointer = 38, AllocAlign = 39, SanitizeSafeStack = 40, + FnRetThunkExtern = 41, } /// LLVMIntPredicate diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index e6e132978ed..714af977fb5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -5,10 +5,11 @@ use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, - InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, - LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, OutFileName, - OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, - SwitchWithOptPath, SymbolManglingVersion, TraitSolver, WasiExecModel, + FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, + LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, + OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, + ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, + WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -758,6 +759,7 @@ fn test_unstable_options_tracking_hash() { tracked!(flatten_format_args, false); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); + tracked!(function_return, FunctionReturn::ThunkExtern); tracked!(function_sections, Some(false)); tracked!(human_readable_cgu_names, true); tracked!(incremental_ignore_spans, true); diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index ad97ede8e9c..834120efa67 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -89,6 +89,7 @@ enum LLVMRustAttribute { AllocatedPointer = 38, AllocAlign = 39, SanitizeSafeStack = 40, + FnRetThunkExtern = 41, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index bf870e28acd..b227dd76f02 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -278,6 +278,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::AllocAlign; case SanitizeSafeStack: return Attribute::SafeStack; + case FnRetThunkExtern: + return Attribute::FnRetThunkExtern; } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index fa1b6f9f13d..3a7959c332e 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -26,6 +26,10 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` +session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models + session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d6e7afb7d09..77874bd9c07 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3164,9 +3164,9 @@ impl PpMode { pub(crate) mod dep_tracking { use super::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression, - ErrorOutputType, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, - LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, + ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, + LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, + OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths, }; use crate::lint; @@ -3273,6 +3273,7 @@ pub(crate) mod dep_tracking { TraitSolver, Polonius, InliningThreshold, + FunctionReturn, ); impl<T1, T2> DepTrackingHash for (T1, T2) @@ -3451,3 +3452,14 @@ impl Default for InliningThreshold { Self::Sometimes(100) } } + +/// The different settings that the `-Zfunction-return` flag can have. +#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] +pub enum FunctionReturn { + /// Keep the function return unmodified. + #[default] + Keep, + + /// Replace returns with jumps to thunk, without emitting the thunk. + ThunkExtern, +} diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 31094e0d266..70ee46ea902 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -436,3 +436,11 @@ pub struct IncompatibleLinkerFlavor { pub flavor: &'static str, pub compatible_list: String, } + +#[derive(Diagnostic)] +#[diag(session_function_return_requires_x86_or_x86_64)] +pub(crate) struct FunctionReturnRequiresX86OrX8664; + +#[derive(Diagnostic)] +#[diag(session_function_return_thunk_extern_requires_non_large_code_model)] +pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4e669c81bf3..68a39de73b7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -430,6 +430,7 @@ mod desc { pub const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; + pub const parse_function_return: &str = "`keep` or `thunk-extern`"; } mod parse { @@ -1359,6 +1360,15 @@ mod parse { slot.push((key.to_string(), value, behavior)); true } + + pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool { + match v { + Some("keep") => *slot = FunctionReturn::Keep, + Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern, + _ => return false, + } + true + } } options! { @@ -1603,6 +1613,8 @@ options! { "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], "set the optimization fuel quota for a crate"), + function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED], + "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"), function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether each function should go in its own section"), future_incompat_test: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 20a67d6d036..e79d7648bef 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,7 +1,7 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ - self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, + self, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath, }; use crate::config::{ErrorOutputType, Input}; @@ -1678,6 +1678,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list }); } } + + if sess.opts.unstable_opts.function_return != FunctionReturn::default() { + if sess.target.arch != "x86" && sess.target.arch != "x86_64" { + sess.emit_err(errors::FunctionReturnRequiresX86OrX8664); + } + } + + // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is + // kept as a `match` to force a change if new ones are added, even if we currently only support + // `thunk-extern` like Clang. + match sess.opts.unstable_opts.function_return { + FunctionReturn::Keep => (), + FunctionReturn::ThunkExtern => { + // FIXME: In principle, the inherited base LLVM target code model could be large, + // but this only checks whether we were passed one explicitly (like Clang does). + if let Some(code_model) = sess.code_model() + && code_model == CodeModel::Large + { + sess.emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel); + } + } + } } /// Holds data on the current incremental compilation session, if there is one. |
