Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Control Flow Guard on Windows. #68180

Merged
merged 1 commit into from
Feb 1, 2020
Merged
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
12 changes: 11 additions & 1 deletion src/librustc_codegen_llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
}

Expand Down
6 changes: 5 additions & 1 deletion src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions src/librustc_codegen_ssa/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {}
Expand Down
18 changes: 16 additions & 2 deletions src/librustc_session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
16 changes: 15 additions & 1 deletion src/librustc_session/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> =
Expand All @@ -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;
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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 changes: 10 additions & 0 deletions src/test/codegen/cfguard_checks.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions src/test/codegen/cfguard_disabled.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions src/test/codegen/cfguard_nochecks.rs
Original file line number Diff line number Diff line change
@@ -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