Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,46 @@ pub(crate) unsafe fn create_module<'ll>(
);
}

// Set stack-protector-guard module flags (equivalent to Clang's -mstack-protector-guard=*)
if let Some(ref guard) = sess.opts.unstable_opts.stack_protector_guard {
if let Some(ref mode) = guard.mode {
llvm::add_module_flag_str(
llmod,
llvm::ModuleFlagMergeBehavior::Error,
"stack-protector-guard",
mode.as_str(),
);
}
if let Some(offset) = guard.offset {
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Error,
"stack-protector-guard-offset",
offset,
);
}
if let Some(ref reg) = guard.reg {
if !reg.is_empty() {
llvm::add_module_flag_str(
llmod,
llvm::ModuleFlagMergeBehavior::Error,
"stack-protector-guard-reg",
reg,
);
}
}
if let Some(ref sym) = guard.symbol {
if !sym.is_empty() {
llvm::add_module_flag_str(
llmod,
llvm::ModuleFlagMergeBehavior::Error,
"stack-protector-guard-symbol",
sym,
);
}
}
}

// Add module flags specified via -Z llvm_module_flag
for (key, value, merge_behavior) in &sess.opts.unstable_opts.llvm_module_flag {
let merge_behavior = match merge_behavior.as_str() {
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ use rustc_session::config::{
InstrumentCoverage, InstrumentMcount, InstrumentXRay, LinkSelfContained, LinkerPluginLto,
LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName,
OutputType, OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius,
ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
build_configuration, build_session_options, rustc_optgroups,
ProcMacroExecutionStrategy, StackProtectorGuard, StackProtectorGuardMode, Strip,
SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, build_configuration,
build_session_options, rustc_optgroups,
};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
Expand Down Expand Up @@ -893,6 +894,15 @@ fn test_unstable_options_tracking_hash() {
tracked!(split_lto_unit, Some(true));
tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
tracked!(stack_protector, StackProtector::All);
tracked!(
stack_protector_guard,
Some(StackProtectorGuard {
mode: Some(StackProtectorGuardMode::Sysreg),
offset: Some(0),
reg: Some("sp_el0".to_string()),
symbol: None,
})
);
tracked!(staticlib_hide_internal_symbols, true);
tracked!(staticlib_rename_internal_symbols, true);
tracked!(teach, true);
Expand Down
31 changes: 29 additions & 2 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1644,6 +1644,31 @@ impl PointerAuthOption {
}
}

#[derive(Clone, Copy, Hash, Debug, PartialEq)]
pub enum StackProtectorGuardMode {
Global,
Tls,
Sysreg,
}

impl StackProtectorGuardMode {
pub fn as_str(&self) -> &'static str {
match self {
Self::Global => "global",
Self::Tls => "tls",
Self::Sysreg => "sysreg",
}
}
}

#[derive(Clone, Hash, Debug, PartialEq, Default)]
pub struct StackProtectorGuard {
pub mode: Option<StackProtectorGuardMode>,
pub offset: Option<u32>,
pub reg: Option<String>,
pub symbol: Option<String>,
}

pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
// First disallow some configuration given on the command line
cfg::disallow_cfgs(sess, &user_cfg);
Expand Down Expand Up @@ -3141,8 +3166,8 @@ pub(crate) mod dep_tracking {
FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentMcount, InstrumentXRay,
LinkerPluginLto, LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload,
OptLevel, OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, PointerAuthOption,
Polonius, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
SymbolManglingVersion, WasiExecModel,
Polonius, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, StackProtectorGuard,
StackProtectorGuardMode, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
};
use crate::lint;
use crate::utils::NativeLib;
Expand Down Expand Up @@ -3240,6 +3265,8 @@ pub(crate) mod dep_tracking {
LocationDetail,
FmtDebug,
BranchProtection,
StackProtectorGuard,
StackProtectorGuardMode,
LanguageIdentifier,
NextSolverConfig,
PatchableFunctionEntry,
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_session/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,12 @@ pub(crate) struct PointerAuthenticationTypeDiscriminationNotSupportedForTarget<'
pub(crate) target_triple: &'a TargetTuple,
}

#[derive(Diagnostic)]
#[diag("`-Z stack-protector-guard` is not supported for the `{$arch}` architecture")]
pub(crate) struct StackProtectorGuardUnsupportedArch {
pub(crate) arch: String,
}

#[derive(Diagnostic)]
#[diag(
"`-Z pointer-authentication` is not supported for target {$target_triple} and will be ignored"
Expand All @@ -395,6 +401,16 @@ pub(crate) struct PointerAuthenticationNotSupportedForTarget<'a> {
pub(crate) target_triple: &'a TargetTuple,
}

#[derive(Diagnostic)]
#[diag(
"invalid value `{$guard}` for `-Z stack-protector-guard` on `{$arch}` architecture, expected one of: {$valid}"
)]
pub(crate) struct StackProtectorGuardInvalidValue {
pub(crate) arch: String,
pub(crate) guard: String,
pub(crate) valid: String,
}

#[derive(Diagnostic)]
#[diag(
"`-Z small-data-threshold` is not supported for target {$target_triple} and will be ignored"
Expand Down
43 changes: 43 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,8 @@ mod desc {
pub(crate) const parse_stack_protector: &str =
"one of (`none` (default), `basic`, `strong`, or `all`)";
pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)";
pub(crate) const parse_stack_protector_guard: &str =
"one of (`global`, `tls`, `sysreg`), optionally with `offset=N`, `reg=R`, `symbol=S`";
pub(crate) const parse_proc_macro_execution_strategy: &str =
"one of supported execution strategies (`same-thread`, or `cross-thread`)";
pub(crate) const parse_inlining_threshold: &str =
Expand Down Expand Up @@ -1993,6 +1995,45 @@ pub mod parse {
true
}

pub(crate) fn parse_stack_protector_guard(
slot: &mut Option<StackProtectorGuard>,
v: Option<&str>,
) -> bool {
match v {
Some(s) => {
let slot = slot.get_or_insert_default();
for opt in s.split(',') {
match opt {
"global" => slot.mode = Some(StackProtectorGuardMode::Global),
"tls" => slot.mode = Some(StackProtectorGuardMode::Tls),
"sysreg" => slot.mode = Some(StackProtectorGuardMode::Sysreg),
s if let Some(value) = s.strip_prefix("offset=") => {
match value.parse::<u32>() {
Ok(n) => slot.offset = Some(n),
Err(_) => return false,
}
}
s if let Some(value) = s.strip_prefix("reg=") => {
if value.is_empty() {
return false;
}
slot.reg = Some(value.to_string());
}
s if let Some(value) = s.strip_prefix("symbol=") => {
if value.is_empty() {
return false;
}
slot.symbol = Some(value.to_string());
}
_ => return false,
}
}
}
_ => return false,
}
true
}

pub(crate) fn parse_collapse_macro_debuginfo(
slot: &mut CollapseMacroDebuginfo,
v: Option<&str>,
Expand Down Expand Up @@ -2806,6 +2847,8 @@ written to standard error output)"),
#[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED] { MITIGATION: StackProtector },
"control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
stack_protector_guard: Option<StackProtectorGuard> = (None, parse_stack_protector_guard, [TRACKED] { TARGET_MODIFIER: StackProtectorGuard },
"stack protector guard settings (`mode[,offset=N][,reg=R][,symbol=S]`; modes: `global`, `tls`, `sysreg`)"),
staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED],
"allow staticlibs to have rust dylib dependencies"),
staticlib_hide_internal_symbols: bool = (false, parse_bool, [TRACKED],
Expand Down
51 changes: 51 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,57 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}
}

if let Some(ref guard) = sess.opts.unstable_opts.stack_protector_guard {
if let Some(ref mode) = guard.mode {
let valid: Option<(&[config::StackProtectorGuardMode], &str)> = match sess.target.arch {
Arch::X86 | Arch::X86_64 => Some((
&[
config::StackProtectorGuardMode::Tls,
config::StackProtectorGuardMode::Global,
],
"tls, global",
)),
Arch::AArch64 => Some((
&[
config::StackProtectorGuardMode::Sysreg,
config::StackProtectorGuardMode::Global,
],
"sysreg, global",
)),
Arch::Arm => Some((
&[
config::StackProtectorGuardMode::Tls,
config::StackProtectorGuardMode::Global,
],
"tls, global",
)),
Arch::RiscV32 | Arch::RiscV64 => Some((
&[
config::StackProtectorGuardMode::Sysreg,
config::StackProtectorGuardMode::Global,
],
"sysreg, global",
)),
_ => None,
};
match valid {
Some((modes, _)) if modes.contains(mode) => {}
Some((_, valid_str)) => {
sess.dcx().emit_err(diagnostics::StackProtectorGuardInvalidValue {
arch: sess.target.arch.to_string(),
guard: mode.as_str().to_string(),
valid: valid_str.to_string(),
});
}
None => {
sess.dcx().emit_err(diagnostics::StackProtectorGuardUnsupportedArch {
arch: sess.target.arch.to_string(),
});
}
}
}
}

if sess.opts.unstable_opts.small_data_threshold.is_some() {
if sess.target.small_data_threshold_support() == SmallDataThresholdSupport::None {
sess.dcx().emit_warn(diagnostics::SmallDataThresholdNotSupportedForTarget {
Expand Down
Loading