diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -3523,7 +3523,8 @@ /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 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -42,6 +42,7 @@ 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 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4859,6 +4859,9 @@ 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 @@ 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 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -552,6 +552,10 @@ // 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 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7076,14 +7076,19 @@ 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 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -509,6 +509,10 @@ 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 --- 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 --- 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 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -51,6 +51,9 @@ 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 ----------------------