mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Add support for Control Flow Guard on Windows.
This patch enables rustc to emit the required LLVM module flags to enable Control Flow Guard metadata (cfguard=1) or metadata and checks (cfguard=2). The LLVM module flags are ignored on unsupported targets and operating systems.
This commit is contained in:
parent
b181835a6b
commit
c0744e1e0c
@ -12,7 +12,7 @@ use rustc_codegen_ssa::traits::*;
|
||||
use crate::callee::get_fn;
|
||||
use rustc::bug;
|
||||
use rustc::mir::mono::CodegenUnit;
|
||||
use rustc::session::config::{self, DebugInfo};
|
||||
use rustc::session::config::{self, CFGuard, DebugInfo};
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::layout::{
|
||||
FnAbiExt, HasParamEnv, LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx,
|
||||
@ -227,6 +227,16 @@ pub unsafe fn create_module(
|
||||
llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
|
||||
}
|
||||
|
||||
// Set module flags to enable Windows Control Flow Guard (/guard:cf) metadata
|
||||
// only (`cfguard=1`) or metadata and checks (`cfguard=2`).
|
||||
match sess.opts.debugging_opts.control_flow_guard {
|
||||
CFGuard::Disabled => {}
|
||||
CFGuard::NoChecks => {
|
||||
llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 1)
|
||||
}
|
||||
CFGuard::Checks => llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 2),
|
||||
}
|
||||
|
||||
llmod
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind};
|
||||
use rustc::middle::dependency_format::Linkage;
|
||||
use rustc::session::config::{
|
||||
self, DebugInfo, OutputFilenames, OutputType, PrintRequest, Sanitizer,
|
||||
self, CFGuard, DebugInfo, OutputFilenames, OutputType, PrintRequest, Sanitizer,
|
||||
};
|
||||
use rustc::session::search_paths::PathKind;
|
||||
/// For all the linkers we support, and information they might
|
||||
@ -1294,6 +1294,10 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
|
||||
cmd.pgo_gen();
|
||||
}
|
||||
|
||||
if sess.opts.debugging_opts.control_flow_guard != CFGuard::Disabled {
|
||||
cmd.control_flow_guard();
|
||||
}
|
||||
|
||||
// FIXME (#2397): At some point we want to rpath our guesses as to
|
||||
// where extern libraries might live, based on the
|
||||
// addl_lib_search_paths
|
||||
|
@ -106,6 +106,7 @@ pub trait Linker {
|
||||
fn no_relro(&mut self);
|
||||
fn optimize(&mut self);
|
||||
fn pgo_gen(&mut self);
|
||||
fn control_flow_guard(&mut self);
|
||||
fn debuginfo(&mut self);
|
||||
fn no_default_libraries(&mut self);
|
||||
fn build_dylib(&mut self, out_filename: &Path);
|
||||
@ -360,6 +361,10 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
self.cmd.arg("__llvm_profile_runtime");
|
||||
}
|
||||
|
||||
fn control_flow_guard(&mut self) {
|
||||
self.sess.warn("Windows Control Flow Guard is not supported by this linker.");
|
||||
}
|
||||
|
||||
fn debuginfo(&mut self) {
|
||||
if let DebugInfo::None = self.sess.opts.debuginfo {
|
||||
// If we are building without debuginfo enabled and we were called with
|
||||
@ -660,6 +665,10 @@ impl<'a> Linker for MsvcLinker<'a> {
|
||||
// Nothing needed here.
|
||||
}
|
||||
|
||||
fn control_flow_guard(&mut self) {
|
||||
self.cmd.arg("/guard:cf");
|
||||
}
|
||||
|
||||
fn debuginfo(&mut self) {
|
||||
// This will cause the Microsoft linker to generate a PDB file
|
||||
// from the CodeView line tables in the object files.
|
||||
@ -862,6 +871,10 @@ impl<'a> Linker for EmLinker<'a> {
|
||||
// noop, but maybe we need something like the gnu linker?
|
||||
}
|
||||
|
||||
fn control_flow_guard(&mut self) {
|
||||
self.sess.warn("Windows Control Flow Guard is not supported by this linker.");
|
||||
}
|
||||
|
||||
fn debuginfo(&mut self) {
|
||||
// Preserve names or generate source maps depending on debug info
|
||||
self.cmd.arg(match self.sess.opts.debuginfo {
|
||||
@ -1058,6 +1071,10 @@ impl<'a> Linker for WasmLd<'a> {
|
||||
|
||||
fn debuginfo(&mut self) {}
|
||||
|
||||
fn control_flow_guard(&mut self) {
|
||||
self.sess.warn("Windows Control Flow Guard is not supported by this linker.");
|
||||
}
|
||||
|
||||
fn no_default_libraries(&mut self) {}
|
||||
|
||||
fn build_dylib(&mut self, _out_filename: &Path) {
|
||||
@ -1233,6 +1250,10 @@ impl<'a> Linker for PtxLinker<'a> {
|
||||
|
||||
fn no_default_libraries(&mut self) {}
|
||||
|
||||
fn control_flow_guard(&mut self) {
|
||||
self.sess.warn("Windows Control Flow Guard is not supported by this linker.");
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, _out_filename: &Path) {}
|
||||
|
||||
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
|
||||
|
@ -70,6 +70,19 @@ impl FromStr for Sanitizer {
|
||||
}
|
||||
}
|
||||
|
||||
/// The different settings that the `-Z control_flow_guard` flag can have.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum CFGuard {
|
||||
/// Do not emit Control Flow Guard metadata or checks.
|
||||
Disabled,
|
||||
|
||||
/// Emit Control Flow Guard metadata but no checks.
|
||||
NoChecks,
|
||||
|
||||
/// Emit Control Flow Guard metadata and checks.
|
||||
Checks,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
|
||||
pub enum OptLevel {
|
||||
No, // -O0
|
||||
@ -1980,8 +1993,8 @@ impl PpMode {
|
||||
/// how the hash should be calculated when adding a new command-line argument.
|
||||
crate mod dep_tracking {
|
||||
use super::{
|
||||
CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, OutputTypes,
|
||||
Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
|
||||
CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
|
||||
OutputTypes, Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
|
||||
};
|
||||
use crate::lint;
|
||||
use crate::utils::NativeLibraryKind;
|
||||
@ -2053,6 +2066,7 @@ crate mod dep_tracking {
|
||||
impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
|
||||
impl_dep_tracking_hash_via_hash!(Sanitizer);
|
||||
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
|
||||
impl_dep_tracking_hash_via_hash!(CFGuard);
|
||||
impl_dep_tracking_hash_via_hash!(TargetTriple);
|
||||
impl_dep_tracking_hash_via_hash!(Edition);
|
||||
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
|
||||
|
@ -263,6 +263,8 @@ macro_rules! options {
|
||||
pub const parse_sanitizer_list: Option<&str> =
|
||||
Some("comma separated list of sanitizers");
|
||||
pub const parse_sanitizer_memory_track_origins: Option<&str> = None;
|
||||
pub const parse_cfguard: Option<&str> =
|
||||
Some("either `disabled`, `nochecks`, or `checks`");
|
||||
pub const parse_linker_flavor: Option<&str> =
|
||||
Some(::rustc_target::spec::LinkerFlavor::one_of());
|
||||
pub const parse_optimization_fuel: Option<&str> =
|
||||
@ -288,7 +290,7 @@ macro_rules! options {
|
||||
#[allow(dead_code)]
|
||||
mod $mod_set {
|
||||
use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
|
||||
SymbolManglingVersion};
|
||||
SymbolManglingVersion, CFGuard};
|
||||
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
@ -499,6 +501,16 @@ macro_rules! options {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some("disabled") => *slot = CFGuard::Disabled,
|
||||
Some("nochecks") => *slot = CFGuard::NoChecks,
|
||||
Some("checks") => *slot = CFGuard::Checks,
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
|
||||
match v.and_then(LinkerFlavor::from_str) {
|
||||
Some(lf) => *slote = Some(lf),
|
||||
@ -950,6 +962,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
(such as entering an empty infinite loop) by inserting llvm.sideeffect"),
|
||||
deduplicate_diagnostics: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
|
||||
"deduplicate identical diagnostics"),
|
||||
control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [UNTRACKED],
|
||||
"use Windows Control Flow Guard (`disabled`, `nochecks` or `checks`)"),
|
||||
no_link: bool = (false, parse_bool, [TRACKED],
|
||||
"compile without linking"),
|
||||
}
|
||||
|
10
src/test/codegen/cfguard_checks.rs
Normal file
10
src/test/codegen/cfguard_checks.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// compile-flags: -Z control_flow_guard=checks
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// A basic test function.
|
||||
pub fn test() {
|
||||
}
|
||||
|
||||
// Ensure the module flag cfguard=2 is present
|
||||
// CHECK: !"cfguard", i32 2
|
10
src/test/codegen/cfguard_disabled.rs
Normal file
10
src/test/codegen/cfguard_disabled.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// compile-flags: -Z control_flow_guard=disabled
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// A basic test function.
|
||||
pub fn test() {
|
||||
}
|
||||
|
||||
// Ensure the module flag cfguard is not present
|
||||
// CHECK-NOT: !"cfguard"
|
10
src/test/codegen/cfguard_nochecks.rs
Normal file
10
src/test/codegen/cfguard_nochecks.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// compile-flags: -Z control_flow_guard=nochecks
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// A basic test function.
|
||||
pub fn test() {
|
||||
}
|
||||
|
||||
// Ensure the module flag cfguard=1 is present
|
||||
// CHECK: !"cfguard", i32 1
|
Loading…
Reference in New Issue
Block a user