From bf7c5f1fae582ff4cc875713695b2dadb1cf5e59 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Fri, 9 Sep 2022 09:17:33 +0300 Subject: [PATCH] [LLD][MinGW] Add --[no-]guard-cf and --[no-]guard-longjmp These will be LLD-specific options to support Control Flow Guard for the MinGW target. They are disabled by default, but enabling `--guard-cf` will also enable `--guard-longjmp` unless `--no-guard-longjmp` is also specified. These options maps to `-guard:cf,[no]longjmp`. Note that these features require the `_load_config_used` symbol to contain the load config directory and be filled with the required symbols. While current versions of mingw-w64 do not supply this symbol, the user can provide their own version of it. Reviewed By: MaskRay, rnk Differential Revision: https://reviews.llvm.org/D132808 --- lld/MinGW/Driver.cpp | 11 +++++++++++ lld/MinGW/Options.td | 5 +++++ lld/docs/ReleaseNotes.rst | 10 +++++++++- lld/test/MinGW/driver.test | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp index 37d2439c3925..90d210e2f880 100644 --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -379,6 +379,17 @@ bool mingw::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, error("unknown parameter: -m" + s); } + if (args.hasFlag(OPT_guard_cf, OPT_no_guard_cf, false)) { + if (args.hasFlag(OPT_guard_longjmp, OPT_no_guard_longjmp, true)) + add("-guard:cf,longjmp"); + else + add("-guard:cf,nolongjmp"); + } else if (args.hasFlag(OPT_guard_longjmp, OPT_no_guard_longjmp, false)) { + auto *a = args.getLastArg(OPT_guard_longjmp); + warn("parameter " + a->getSpelling() + + " only takes effect when used with --guard-cf"); + } + for (auto *a : args.filtered(OPT_mllvm)) add("-mllvm:" + StringRef(a->getValue())); diff --git a/lld/MinGW/Options.td b/lld/MinGW/Options.td index cc94b93e388a..923b9cce3d18 100644 --- a/lld/MinGW/Options.td +++ b/lld/MinGW/Options.td @@ -141,6 +141,11 @@ defm pdb: Eq<"pdb", "Output PDB debug info file, chosen implicitly if the argume defm thinlto_cache_dir: EqLong<"thinlto-cache-dir", "Path to ThinLTO cached object file directory">; defm Xlink : Eq<"Xlink", "Pass to the COFF linker">, MetaVarName<"">; +defm guard_cf : B<"guard-cf", "Enable Control Flow Guard" , + "Do not enable Control Flow Guard (default)">; +defm guard_longjmp : B<"guard-longjmp", + "Enable Control Flow Guard long jump hardening (default for --guard-cf)" , + "Do not enable Control Flow Guard long jump hardening">; // Alias def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias; diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index aedfdfaf2c81..325c8abd0bd8 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -37,7 +37,15 @@ COFF Improvements MinGW Improvements ------------------ -* ... +* The lld-specific options ``--guard-cf``, ``--no-guard-cf``, + ``--guard-longjmp`` and ``--no-guard-longjmp`` has been added to allow + enabling Control Flow Guard and long jump hardening. These options are + disabled by default, but enabling ``--guard-cf`` will also enable + ``--guard-longjmp`` unless ``--no-guard-longjmp`` is also specified. + ``--guard-longjmp`` depends on ``--guard-cf`` and cannot be used by itself. + Note that these features require the ``_load_config_used`` symbol to contain + the load config directory and be filled with the required symbols. + (`D132808 `_) MachO Improvements ------------------ diff --git a/lld/test/MinGW/driver.test b/lld/test/MinGW/driver.test index 9c56bfa42f6b..de222803530a 100644 --- a/lld/test/MinGW/driver.test +++ b/lld/test/MinGW/driver.test @@ -356,3 +356,18 @@ RUN: ld.lld -### foo.o -m i386pep -heap 8388608,16384 2>&1 | FileCheck -check-pr RUN: ld.lld -### foo.o -m i386pep --heap 8388608,16384 2>&1 | FileCheck -check-prefix=HEAP %s RUN: ld.lld -### foo.o -m i386pep --heap=8388608,16384 2>&1 | FileCheck -check-prefix=HEAP %s HEAP: -heap:8388608,16384 + +RUN: ld.lld -### foo.o -m i386pep --no-guard-cf 2>&1 | FileCheck -check-prefix=NO_GUARD_CF %s +RUN: ld.lld -### foo.o -m i386pep --no-guard-cf --no-guard-longjmp 2>&1 | FileCheck -check-prefix=NO_GUARD_CF %s +NO_GUARD_CF-NOT: -guard: + +RUN: ld.lld -### foo.o -m i386pep --guard-cf 2>&1 | FileCheck -check-prefix=GUARD_CF %s +RUN: ld.lld -### foo.o -m i386pep --guard-cf --guard-longjmp 2>&1 | FileCheck -check-prefix=GUARD_CF %s +GUARD_CF: -guard:cf,longjmp + +RUN: ld.lld -### foo.o -m i386pep --guard-cf --no-guard-longjmp 2>&1 | FileCheck -check-prefix=GUARD_CF_NOLONGJMP %s +GUARD_CF_NOLONGJMP: -guard:cf,nolongjmp + +RUN: ld.lld -### foo.o -m i386pep --guard-longjmp 2>&1 | FileCheck -check-prefix=GUARD_LONGJMP_NO_CF %s +RUN: ld.lld -### foo.o -m i386pep --no-guard-cf --guard-longjmp 2>&1 | FileCheck -check-prefix=GUARD_LONGJMP_NO_CF %s +GUARD_LONGJMP_NO_CF: warning: parameter --guard-longjmp only takes effect when used with --guard-cf