From e7e67c930ae59151affcd57bd49d650e4dac3468 Mon Sep 17 00:00:00 2001 From: "Wang, Pengfei" Date: Wed, 3 Mar 2021 10:38:21 +0800 Subject: [PATCH] Add Windows ehcont section support (/guard:ehcont). Add option /guard:ehcont Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D96709 --- clang/docs/UsersManual.rst | 3 ++- clang/include/clang/Basic/CodeGenOptions.def | 1 + clang/include/clang/Driver/Options.td | 6 +++++- clang/lib/CodeGen/CodeGenModule.cpp | 4 ++++ clang/lib/Driver/ToolChains/Clang.cpp | 9 +++++++-- clang/lib/Driver/ToolChains/MSVC.cpp | 4 ++++ clang/test/CodeGen/cfguardtable.c | 18 ++++++++++-------- clang/test/Driver/cl-options.c | 7 +++++++ llvm/docs/ReleaseNotes.rst | 3 +++ 9 files changed, 43 insertions(+), 12 deletions(-) diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index b762bf9..c668645 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -3523,7 +3523,8 @@ Execute ``clang-cl /?`` to see a list of supported options: /Gs Use stack probes (default) /Gs Set stack probe size (default 4096) /guard: Enable Control Flow Guard with /guard:cf, - or only the table with /guard:cf,nochecks + or only the table with /guard:cf,nochecks. + Enable EH Continuation Guard with /guard:ehcont /Gv Set __vectorcall as a default calling convention /Gw- Don't put each data item in its own section /Gw Put each data item in its own section diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 832f7fa..50503db 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -42,6 +42,7 @@ CODEGENOPT(Backchain , 1, 0) ///< -mbackchain CODEGENOPT(IgnoreXCOFFVisibility , 1, 0) ///< -mignore-xcoff-visibility CODEGENOPT(ControlFlowGuardNoChecks , 1, 0) ///< -cfguard-no-checks CODEGENOPT(ControlFlowGuard , 1, 0) ///< -cfguard +CODEGENOPT(EHContGuard , 1, 0) ///< -ehcontguard CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors. CODEGENOPT(RegisterGlobalDtorsWithAtExit, 1, 1) ///< Use atexit or __cxa_atexit to register global destructors. CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 72213ed..2f57895 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4859,6 +4859,9 @@ def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">, def cfguard : Flag<["-"], "cfguard">, HelpText<"Emit Windows Control Flow Guard tables and checks">, MarshallingInfoFlag>; +def ehcontguard : Flag<["-"], "ehcontguard">, + HelpText<"Emit Windows EH Continuation Guard tables">, + MarshallingInfoFlag>; def fdenormal_fp_math_f32_EQ : Joined<["-"], "fdenormal-fp-math-f32=">, Group; @@ -5857,7 +5860,8 @@ def _SLASH_Fo : CLCompileJoined<"Fo">, HelpText<"Set output object file (with /c)">, MetaVarName<"">; def _SLASH_guard : CLJoined<"guard:">, - HelpText<"Enable Control Flow Guard with /guard:cf, or only the table with /guard:cf,nochecks">; + HelpText<"Enable Control Flow Guard with /guard:cf, or only the table with /guard:cf,nochecks. " + "Enable EH Continuation Guard with /guard:ehcont">; def _SLASH_GX : CLFlag<"GX">, HelpText<"Deprecated; use /EHsc">; def _SLASH_GX_ : CLFlag<"GX-">, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 802a13f..b23d995 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -552,6 +552,10 @@ void CodeGenModule::Release() { // Function ID tables for Control Flow Guard (cfguard=1). getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 1); } + if (CodeGenOpts.EHContGuard) { + // Function ID tables for EH Continuation Guard. + getModule().addModuleFlag(llvm::Module::Warning, "ehcontguard", 1); + } if (CodeGenOpts.OptimizationLevel > 0 && CodeGenOpts.StrictVTablePointers) { // We don't support LTO with 2 with different StrictVTablePointers // FIXME: we could support it by stripping all the information introduced diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index df2b207..eb09d72 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7076,14 +7076,19 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { StringRef GuardArgs = A->getValue(); - // The only valid options are "cf", "cf,nochecks", and "cf-". + // The only valid options are "cf", "cf,nochecks", "cf-", "ehcont" and + // "ehcont-". if (GuardArgs.equals_lower("cf")) { // Emit CFG instrumentation and the table of address-taken functions. CmdArgs.push_back("-cfguard"); } else if (GuardArgs.equals_lower("cf,nochecks")) { // Emit only the table of address-taken functions. CmdArgs.push_back("-cfguard-no-checks"); - } else if (GuardArgs.equals_lower("cf-")) { + } else if (GuardArgs.equals_lower("ehcont")) { + // Emit EH continuation table. + CmdArgs.push_back("-ehcontguard"); + } else if (GuardArgs.equals_lower("cf-") || + GuardArgs.equals_lower("ehcont-")) { // Do nothing, but we might want to emit a security warning in future. } else { D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs; diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index c95c5b6..96de023 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -509,6 +509,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-guard:cf"); } else if (GuardArgs.equals_lower("cf-")) { CmdArgs.push_back("-guard:cf-"); + } else if (GuardArgs.equals_lower("ehcont")) { + CmdArgs.push_back("-guard:ehcont"); + } else if (GuardArgs.equals_lower("ehcont-")) { + CmdArgs.push_back("-guard:ehcont-"); } } diff --git a/clang/test/CodeGen/cfguardtable.c b/clang/test/CodeGen/cfguardtable.c index 05284f6..c0212ae 100644 --- a/clang/test/CodeGen/cfguardtable.c +++ b/clang/test/CodeGen/cfguardtable.c @@ -1,8 +1,10 @@ -// RUN: %clang_cc1 -cfguard-no-checks -emit-llvm %s -o - | FileCheck %s -check-prefix=CFGUARDNOCHECKS -// RUN: %clang_cc1 -cfguard -emit-llvm %s -o - | FileCheck %s -check-prefix=CFGUARD - -void f() {} - -// Check that the cfguard metadata flag gets correctly set on the module. -// CFGUARDNOCHECKS: !"cfguard", i32 1} -// CFGUARD: !"cfguard", i32 2} +// RUN: %clang_cc1 -cfguard-no-checks -emit-llvm %s -o - | FileCheck %s -check-prefix=CFGUARDNOCHECKS +// RUN: %clang_cc1 -cfguard -emit-llvm %s -o - | FileCheck %s -check-prefix=CFGUARD +// RUN: %clang_cc1 -ehcontguard -emit-llvm %s -o - | FileCheck %s -check-prefix=EHCONTGUARD + +void f() {} + +// Check that the cfguard metadata flag gets correctly set on the module. +// CFGUARDNOCHECKS: !"cfguard", i32 1} +// CFGUARD: !"cfguard", i32 2} +// EHCONTGUARD: !"ehcontguard", i32 1} diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 0e07ea4..7d83b3d 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -614,6 +614,13 @@ // RUN: %clang_cl /guard:nochecks -### -- %s 2>&1 | FileCheck -check-prefix=CFGUARDNOCHECKSINVALID %s // CFGUARDNOCHECKSINVALID: invalid value 'nochecks' in '/guard:' +// RUN: %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=NOEHCONTGUARD %s +// RUN: %clang_cl /guard:ehcont- -### -- %s 2>&1 | FileCheck -check-prefix=NOEHCONTGUARD %s +// NOEHCONTGUARD-NOT: -ehcontguard + +// RUN: %clang_cl /guard:ehcont -### -- %s 2>&1 | FileCheck -check-prefix=EHCONTGUARD %s +// EHCONTGUARD: -ehcontguard + // RUN: %clang_cl /guard:foo -### -- %s 2>&1 | FileCheck -check-prefix=CFGUARDINVALID %s // CFGUARDINVALID: invalid value 'foo' in '/guard:' diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 1de11f0..411505c 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -51,6 +51,9 @@ Non-comprehensive list of changes in this release Makes programs 10x faster by doing Special New Thing. +* Windows Control-flow Enforcement Technology: the ``-ehcontguard`` option now + emits valid unwind entrypoints which are validated when the context is being + set during exception handling. Changes to the LLVM IR ---------------------- -- 2.7.4