[clang] [llvm] [win] Add a flag to control the Control Flow Guard mechanism on Windows (PR #176276)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 15 16:17:32 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: Daniel Paoliello (dpaoliello)
<details>
<summary>Changes</summary>
Adds a new Clang and CC1 flag to control the Control Flow Guard mechanism on Windows: `-fwin-cfg-mechanism`. This can be set to `automatic` (use the targat arch default), `force-dispatch` or `force-check`.
Also adds the support for the equivalent MSVC flag `/d2guardcfgdispatch`.
NOTE: Arm64EC only supports the check mechanism. It should be noted that MSVC emits the "dispatch" name for the call checker (for legacy reasons) but uses the check mechanism.
---
Patch is 30.22 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/176276.diff
23 Files Affected:
- (modified) clang/include/clang/Basic/CodeGenOptions.def (+4)
- (modified) clang/include/clang/Basic/CodeGenOptions.h (+1)
- (modified) clang/include/clang/Options/Options.td (+12)
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+13-2)
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+9)
- (added) clang/test/CodeGen/cfguard-mechanism.c (+11)
- (modified) clang/test/Driver/cl-options.c (+6)
- (modified) llvm/include/llvm/IR/Module.h (+3)
- (modified) llvm/include/llvm/Support/CodeGen.h (+17)
- (modified) llvm/include/llvm/Transforms/CFGuard.h (+2-5)
- (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+2-2)
- (modified) llvm/lib/CodeGen/CFGuardLongjmp.cpp (+2-1)
- (modified) llvm/lib/IR/Module.cpp (+7)
- (modified) llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp (+4-5)
- (modified) llvm/lib/Target/AArch64/AArch64TargetMachine.cpp (+1-1)
- (modified) llvm/lib/Target/ARM/ARMTargetMachine.cpp (+1-1)
- (modified) llvm/lib/Target/X86/X86CallingConv.td (+3-1)
- (modified) llvm/lib/Target/X86/X86RegisterInfo.cpp (+7-3)
- (modified) llvm/lib/Target/X86/X86TargetMachine.cpp (+1-5)
- (modified) llvm/lib/Transforms/CFGuard/CFGuard.cpp (+32-31)
- (modified) llvm/test/CodeGen/AArch64/cfguard-module-flag.ll (+26-10)
- (modified) llvm/test/CodeGen/ARM/cfguard-module-flag.ll (+26-10)
- (modified) llvm/test/CodeGen/X86/cfguard-module-flag.ll (+32-11)
``````````diff
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index baf8b093c10e6..3dad7dd1d551f 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -505,6 +505,10 @@ CODEGENOPT(AllResourcesBound, 1, 0, Benign)
ENUM_CODEGENOPT(WinX64EHUnwindV2, WinX64EHUnwindV2Mode,
2, WinX64EHUnwindV2Mode::Disabled, Benign)
+/// Controls the mechanism used for Control Flow Guard (CFG) on Windows.
+ENUM_CODEGENOPT(WinControlFlowGuardMechanism, ControlFlowGuardMechanism,
+ 2, ControlFlowGuardMechanism::Automatic, Benign)
+
/// FIXME: Make DebugOptions its own top-level .def file.
#include "DebugOptions.def"
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index c60ca507ff917..365dd4fe2eac3 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -66,6 +66,7 @@ class CodeGenOptionsBase {
using VectorLibrary = llvm::driver::VectorLibrary;
using ZeroCallUsedRegsKind = llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind;
using WinX64EHUnwindV2Mode = llvm::WinX64EHUnwindV2Mode;
+ using ControlFlowGuardMechanism = llvm::ControlFlowGuardMechanism;
using DebugCompressionType = llvm::DebugCompressionType;
using EmitDwarfUnwindType = llvm::EmitDwarfUnwindType;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index d4dd71b9d1bea..b74cac8cb44f8 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2257,6 +2257,14 @@ def winx64_eh_unwindv2
NormalizedValues<["Disabled", "BestEffort", "Required"]>,
NormalizedValuesScope<"llvm::WinX64EHUnwindV2Mode">,
MarshallingInfoEnum<CodeGenOpts<"WinX64EHUnwindV2">, "Disabled">;
+def win_cfg_mechanism
+ : Joined<["-"], "fwin-cfg-mechanism=">, Group<f_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Sets the mechanism to use for Control Flow Guard on Windows">,
+ Values<"automatic,force-dispatch,force-check">,
+ NormalizedValues<["Automatic", "ForceDispatch", "ForceCheck"]>,
+ NormalizedValuesScope<"llvm::ControlFlowGuardMechanism">,
+ MarshallingInfoEnum<CodeGenOpts<"WinControlFlowGuardMechanism">, "Automatic">;
def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group<f_Group>,
Visibility<[ClangOption, CLOption]>,
HelpText<"Allows control over excess precision on targets where native "
@@ -9382,6 +9390,10 @@ def _SLASH_d2epilogunwind : CLFlag<"d2epilogunwind">,
HelpText<"Best effort generate unwind v2 (epilog) information for x64 Windows">;
def _SLASH_d2epilogunwindrequirev2 : CLFlag<"d2epilogunwindrequirev2">,
HelpText<"Require generation of unwind v2 (epilog) information for x64 Windows">;
+def _SLASH_d2guardcfgdispatch : CLFlag<"d2guardcfgdispatch">,
+ HelpText<"Force Control Flow Guard to use the dispatch pattern">;
+def _SLASH_d2guardcfgdispatch_ : CLFlag<"d2guardcfgdispatch-">,
+ HelpText<"Force Control Flow Guard to use the check pattern">;
def _SLASH_EH : CLJoined<"EH">, HelpText<"Set exception handling model">;
def _SLASH_EP : CLFlag<"EP">,
HelpText<"Disable linemarker output and preprocess to stdout">;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 614bca627e03c..99242afd1c2b8 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1123,10 +1123,21 @@ void CodeGenModule::Release() {
}
if (CodeGenOpts.ControlFlowGuard) {
// Function ID tables and checks for Control Flow Guard (cfguard=2).
- getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 2);
+ getModule().addModuleFlag(
+ llvm::Module::Warning, "cfguard",
+ static_cast<unsigned>(llvm::ControlFlowGuardMode::Enabled));
} else if (CodeGenOpts.ControlFlowGuardNoChecks) {
// Function ID tables for Control Flow Guard (cfguard=1).
- getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 1);
+ getModule().addModuleFlag(
+ llvm::Module::Warning, "cfguard",
+ static_cast<unsigned>(llvm::ControlFlowGuardMode::TableOnly));
+ }
+ if (CodeGenOpts.getWinControlFlowGuardMechanism() !=
+ llvm::ControlFlowGuardMechanism::Automatic) {
+ // Specify the Control Flow Guard mechanism to use on Windows.
+ getModule().addModuleFlag(
+ llvm::Module::Warning, "cfguard-mechanism",
+ static_cast<unsigned>(CodeGenOpts.getWinControlFlowGuardMechanism()));
}
if (CodeGenOpts.EHContGuard) {
// Function ID tables for EH Continuation Guard.
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 4ca98600d6e93..706910d4bc02c 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7393,6 +7393,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Unwind v2 (epilog) information for x64 Windows.
Args.AddLastArg(CmdArgs, options::OPT_winx64_eh_unwindv2);
+ // Control Flow Guard mechanism for Windows.
+ Args.AddLastArg(CmdArgs, options::OPT_win_cfg_mechanism);
+
// C++ "sane" operator new.
Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new);
@@ -8522,6 +8525,12 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
A->claim();
}
+ // Unwind v2 (epilog) information for x64 Windows.
+ if (Args.hasArg(options::OPT__SLASH_d2guardcfgdispatch_))
+ CmdArgs.push_back("-fwin-cfg-mechanism=force-check");
+ else if (Args.hasArg(options::OPT__SLASH_d2guardcfgdispatch))
+ CmdArgs.push_back("-fwin-cfg-mechanism=force-dispatch");
+
for (const auto &FuncOverride :
Args.getAllArgValues(options::OPT__SLASH_funcoverride)) {
CmdArgs.push_back(Args.MakeArgString(
diff --git a/clang/test/CodeGen/cfguard-mechanism.c b/clang/test/CodeGen/cfguard-mechanism.c
new file mode 100644
index 0000000000000..c6db8ff5135b1
--- /dev/null
+++ b/clang/test/CodeGen/cfguard-mechanism.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s -check-prefix=AUTOMATIC
+// RUN: %clang_cc1 -fwin-cfg-mechanism=automatic -emit-llvm %s -o - | FileCheck %s -check-prefix=AUTOMATIC
+// RUN: %clang_cc1 -fwin-cfg-mechanism=force-dispatch -emit-llvm %s -o - | FileCheck %s -check-prefix=FORCEDISPATCH
+// RUN: %clang_cc1 -fwin-cfg-mechanism=force-check -emit-llvm %s -o - | FileCheck %s -check-prefix=FORCECHECK
+// RUN: %clang -fwin-cfg-mechanism=force-dispatch -S -emit-llvm %s -o - | FileCheck %s -check-prefix=FORCEDISPATCH
+
+void f(void) {}
+
+// FORCECHECK: !"cfguard-mechanism", i32 1}
+// FORCEDISPATCH: !"cfguard-mechanism", i32 2}
+// AUTOMATIC-NOT: "cfguard-mechanism"
diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c
index 1b1169b71554a..bd25184fb9240 100644
--- a/clang/test/Driver/cl-options.c
+++ b/clang/test/Driver/cl-options.c
@@ -845,4 +845,10 @@
// FUNCOVERRIDE: -loader-replaceable-function=override_me1
// FUNCOVERRIDE-SAME: -loader-replaceable-function=override_me2
+// RUN: %clang_cl /d2guardcfgdispatch /c -### -- %s 2>&1 | FileCheck %s --check-prefix=GUARDCFGDISPATCH
+// GUARDCFGDISPATCH: -fwin-cfg-mechanism=force-dispatch
+
+// RUN: %clang_cl /d2guardcfgdispatch- /c -### -- %s 2>&1 | FileCheck %s --check-prefix=GUARDCFGDISPATCHNEG
+// GUARDCFGDISPATCHNEG: -fwin-cfg-mechanism=force-check
+
void f(void) { }
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index ac6c20b81d68c..7156a83c9f3cc 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -1056,6 +1056,9 @@ class LLVM_ABI Module {
/// Get how unwind v2 (epilog) information should be generated for x64
/// Windows.
WinX64EHUnwindV2Mode getWinX64EHUnwindV2Mode() const;
+
+ /// Gets the Control Flow Guard mode.
+ ControlFlowGuardMode getControlFlowGuardMode() const;
};
/// Given "llvm.used" or "llvm.compiler.used" as a global name, collect the
diff --git a/llvm/include/llvm/Support/CodeGen.h b/llvm/include/llvm/Support/CodeGen.h
index 848796ef574f8..9626782729f3c 100644
--- a/llvm/include/llvm/Support/CodeGen.h
+++ b/llvm/include/llvm/Support/CodeGen.h
@@ -173,6 +173,23 @@ namespace llvm {
Required = 2,
};
+ enum class ControlFlowGuardMode {
+ // Don't enable Control Flow Guard.
+ Disabled = 0,
+ // Emit the Control Flow Guard tables in the binary, but don't emit any
+ // checks.
+ TableOnly = 1,
+ // Enable Control Flow Guard checks and emit the tables.
+ Enabled = 2,
+ };
+
+ enum class ControlFlowGuardMechanism {
+ // Choose the mechanism automatically based on the target.
+ Automatic = 0,
+ ForceCheck = 1,
+ ForceDispatch = 2,
+ };
+
} // namespace llvm
#endif
diff --git a/llvm/include/llvm/Transforms/CFGuard.h b/llvm/include/llvm/Transforms/CFGuard.h
index b81db8f487965..6af0f351b75d0 100644
--- a/llvm/include/llvm/Transforms/CFGuard.h
+++ b/llvm/include/llvm/Transforms/CFGuard.h
@@ -29,11 +29,8 @@ class CFGuardPass : public PassInfoMixin<CFGuardPass> {
Mechanism GuardMechanism;
};
-/// Insert Control FLow Guard checks on indirect function calls.
-FunctionPass *createCFGuardCheckPass();
-
-/// Insert Control FLow Guard dispatches on indirect function calls.
-FunctionPass *createCFGuardDispatchPass();
+/// Insert Control Flow Guard checks on indirect function calls.
+FunctionPass *createCFGuardPass();
bool isCFGuardFunction(const GlobalValue *GV);
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index d96294e06d579..5990c2a2ba26a 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -665,7 +665,7 @@ bool AsmPrinter::doInitialization(Module &M) {
Handlers.push_back(std::unique_ptr<EHStreamer>(ES));
// Emit tables for any value of cfguard flag (i.e. cfguard=1 or cfguard=2).
- if (mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("cfguard")))
+ if (M.getControlFlowGuardMode() != ControlFlowGuardMode::Disabled)
EHHandlers.push_back(std::make_unique<WinCFGuard>(this));
for (auto &Handler : Handlers)
@@ -5088,7 +5088,7 @@ void AsmPrinter::emitCOFFFeatureSymbol(Module &M) {
Feat00Value |= COFF::Feat00Flags::SafeSEH;
}
- if (M.getModuleFlag("cfguard")) {
+ if (M.getControlFlowGuardMode() != ControlFlowGuardMode::Disabled) {
// Object is CFG-aware.
Feat00Value |= COFF::Feat00Flags::GuardCF;
}
diff --git a/llvm/lib/CodeGen/CFGuardLongjmp.cpp b/llvm/lib/CodeGen/CFGuardLongjmp.cpp
index 04de011400568..639d0537c2cc1 100644
--- a/llvm/lib/CodeGen/CFGuardLongjmp.cpp
+++ b/llvm/lib/CodeGen/CFGuardLongjmp.cpp
@@ -62,7 +62,8 @@ FunctionPass *llvm::createCFGuardLongjmpPass() { return new CFGuardLongjmp(); }
bool CFGuardLongjmp::runOnMachineFunction(MachineFunction &MF) {
// Skip modules for which the cfguard flag is not set.
- if (!MF.getFunction().getParent()->getModuleFlag("cfguard"))
+ if (MF.getFunction().getParent()->getControlFlowGuardMode() ==
+ ControlFlowGuardMode::Disabled)
return false;
// Skip functions that do not have calls to _setjmp.
diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp
index 7360d0fa1f86a..11dc68e0e4751 100644
--- a/llvm/lib/IR/Module.cpp
+++ b/llvm/lib/IR/Module.cpp
@@ -940,3 +940,10 @@ WinX64EHUnwindV2Mode Module::getWinX64EHUnwindV2Mode() const {
return static_cast<WinX64EHUnwindV2Mode>(CI->getZExtValue());
return WinX64EHUnwindV2Mode::Disabled;
}
+
+ControlFlowGuardMode Module::getControlFlowGuardMode() const {
+ Metadata *MD = getModuleFlag("cfguard");
+ if (auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(MD))
+ return static_cast<ControlFlowGuardMode>(CI->getZExtValue());
+ return ControlFlowGuardMode::Disabled;
+}
diff --git a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
index d0c4b1b9f83fd..c27a693ceecc1 100644
--- a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
@@ -75,7 +75,7 @@ class AArch64Arm64ECCallLowering : public ModulePass {
bool runOnModule(Module &M) override;
private:
- int cfguard_module_flag = 0;
+ ControlFlowGuardMode CFGuardModuleFlag = ControlFlowGuardMode::Disabled;
FunctionType *GuardFnType = nullptr;
FunctionType *DispatchFnType = nullptr;
Constant *GuardFnCFGlobal = nullptr;
@@ -758,7 +758,8 @@ void AArch64Arm64ECCallLowering::lowerCall(CallBase *CB) {
// Load the global symbol as a pointer to the check function.
Value *GuardFn;
- if (cfguard_module_flag == 2 && !CB->hasFnAttr("guard_nocf"))
+ if ((CFGuardModuleFlag == ControlFlowGuardMode::Enabled) &&
+ !CB->hasFnAttr("guard_nocf"))
GuardFn = GuardFnCFGlobal;
else
GuardFn = GuardFnGlobal;
@@ -794,9 +795,7 @@ bool AArch64Arm64ECCallLowering::runOnModule(Module &Mod) {
M = &Mod;
// Check if this module has the cfguard flag and read its value.
- if (auto *MD =
- mdconst::extract_or_null<ConstantInt>(M->getModuleFlag("cfguard")))
- cfguard_module_flag = MD->getZExtValue();
+ CFGuardModuleFlag = M->getControlFlowGuardMode();
PtrTy = PointerType::getUnqual(M->getContext());
I64Ty = Type::getInt64Ty(M->getContext());
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 3aba866458830..09795672da1cf 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -674,7 +674,7 @@ void AArch64PassConfig::addIRPasses() {
if (TM->getTargetTriple().isWindowsArm64EC())
addPass(createAArch64Arm64ECCallLoweringPass());
else
- addPass(createCFGuardCheckPass());
+ addPass(createCFGuardPass());
}
if (TM->Options.JMCInstrument)
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index 590d4c70592f8..aadf8624c7c8c 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -384,7 +384,7 @@ void ARMPassConfig::addIRPasses() {
// Add Control Flow Guard checks.
if (TM->getTargetTriple().isOSWindows())
- addPass(createCFGuardCheckPass());
+ addPass(createCFGuardPass());
if (TM->Options.JMCInstrument)
addPass(createJMCInstrumenterPass());
diff --git a/llvm/lib/Target/X86/X86CallingConv.td b/llvm/lib/Target/X86/X86CallingConv.td
index f020e0b55141c..7d24126f820f8 100644
--- a/llvm/lib/Target/X86/X86CallingConv.td
+++ b/llvm/lib/Target/X86/X86CallingConv.td
@@ -1217,8 +1217,10 @@ def CSR_Win32_CFGuard_Check_NoSSE : CalleeSavedRegs<(add CSR_32_RegCall_NoSSE, E
def CSR_Win32_CFGuard_Check : CalleeSavedRegs<(add CSR_32_RegCall, ECX)>;
def CSR_Win64_RegCall_NoSSE : CalleeSavedRegs<(add RBX, RBP,
(sequence "R%u", 10, 15))>;
-def CSR_Win64_RegCall : CalleeSavedRegs<(add CSR_Win64_RegCall_NoSSE,
+def CSR_Win64_RegCall : CalleeSavedRegs<(add CSR_Win64_RegCall_NoSSE,
(sequence "XMM%u", 8, 15))>;
+def CSR_Win64_CFGuard_Check_NoSSE : CalleeSavedRegs<(add CSR_Win64_RegCall_NoSSE, RCX)>;
+def CSR_Win64_CFGuard_Check : CalleeSavedRegs<(add CSR_Win64_RegCall, RCX)>;
def CSR_SysV64_RegCall_NoSSE : CalleeSavedRegs<(add RBX, RBP,
(sequence "R%u", 12, 15))>;
def CSR_SysV64_RegCall : CalleeSavedRegs<(add CSR_SysV64_RegCall_NoSSE,
diff --git a/llvm/lib/Target/X86/X86RegisterInfo.cpp b/llvm/lib/Target/X86/X86RegisterInfo.cpp
index 72f38133e21ff..635c06440c873 100644
--- a/llvm/lib/Target/X86/X86RegisterInfo.cpp
+++ b/llvm/lib/Target/X86/X86RegisterInfo.cpp
@@ -434,9 +434,13 @@ X86RegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CSR_32_RegCall_NoSSE_RegMask);
}
case CallingConv::CFGuard_Check:
- assert(!Is64Bit && "CFGuard check mechanism only used on 32-bit X86");
- return (HasSSE ? CSR_Win32_CFGuard_Check_RegMask
- : CSR_Win32_CFGuard_Check_NoSSE_RegMask);
+ if (Is64Bit) {
+ return (HasSSE ? CSR_Win64_CFGuard_Check_RegMask
+ : CSR_Win64_CFGuard_Check_NoSSE_RegMask);
+ } else {
+ return (HasSSE ? CSR_Win32_CFGuard_Check_RegMask
+ : CSR_Win32_CFGuard_Check_NoSSE_RegMask);
+ }
case CallingConv::Cold:
if (Is64Bit)
return CSR_64_MostRegs_RegMask;
diff --git a/llvm/lib/Target/X86/X86TargetMachine.cpp b/llvm/lib/Target/X86/X86TargetMachine.cpp
index d5907d55998b5..bf9ec458acf27 100644
--- a/llvm/lib/Target/X86/X86TargetMachine.cpp
+++ b/llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -441,11 +441,7 @@ void X86PassConfig::addIRPasses() {
// Add Control Flow Guard checks.
const Triple &TT = TM->getTargetTriple();
if (TT.isOSWindows()) {
- if (TT.isX86_64()) {
- addPass(createCFGuardDispatchPass());
- } else {
- addPass(createCFGuardCheckPass());
- }
+ addPass(createCFGuardPass());
}
if (TM->Options.JMCInstrument)
diff --git a/llvm/lib/Transforms/CFGuard/CFGuard.cpp b/llvm/lib/Transforms/CFGuard/CFGuard.cpp
index 46456706d46a1..b648b4f862c65 100644
--- a/llvm/lib/Transforms/CFGuard/CFGuard.cpp
+++ b/llvm/lib/Transforms/CFGuard/CFGuard.cpp
@@ -38,24 +38,11 @@ namespace {
/// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes.
/// These checks ensure that the target address corresponds to the start of an
-/// address-taken function. X86_64 targets use the Mechanism::Dispatch
-/// mechanism. X86, ARM, and AArch64 targets use the Mechanism::Check machanism.
+/// address-taken function.
class CFGuardImpl {
public:
using Mechanism = CFGuardPass::Mechanism;
- CFGuardImpl(Mechanism M) : GuardMechanism(M) {
- // Get or insert the guard check or dispatch global symbols.
- switch (GuardMechanism) {
- case Mechanism::Check:
- GuardFnName = GuardCheckFunctionName;
- break;
- case Mechanism::Dispatch:
- GuardFnName = GuardDispatchFunctionName;
- break;
- }
- }
-
/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
/// check mechanism. When the image is loaded, the loader puts the appropriate
/// guard check function pointer in the __guard_check_icall_fptr global
@@ -147,8 +134,7 @@ class CFGuardImpl {
private:
// Only add checks if the module has the cfguard=2 flag.
- int CFGuardModuleFlag = 0;
- StringRef GuardFnName;
+ ControlFlowGuardMode CFGuardModuleFlag = ControlFlowGuardMode::Disabled;
Mechanism GuardMechanism = Mechanism::Check;
FunctionType *GuardFnType = nullptr;
PointerType *GuardFnPtrType = nullptr;
@@ -162,7 +148,7 @@ class CFGuard : public FunctionPass {
static char ID;
// Default constructor required for the INITIALIZE_PASS macro.
- CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {}
+ CFGuard() : FunctionPass(ID) {}
bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
@@ -233,20 +219,42 @@ void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {
bool CFGuardImpl::doInitialization(Module &M) {
// Check if this module has the cfguard flag and read its value.
- if (auto *MD =
- mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("cfguard")))
- CFGuardModuleFlag = MD->getZExtValue();
+ CFGuardModuleFlag = M.getControlFlowGuardMode();
// Skip modules for which CFGuard checks have been disabled.
- if (CFGuardModuleFlag != 2)
+ if (CFGuardModuleFlag != ControlFlowGuardMode::Enabled)
return false;
+ // Determine the guard mechanism to use.
+ ControlFlowGuardMechanism MechanismOverride =
+ ControlFlowGuardMechanism::Automatic;
+ if (auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(
+ M.getModuleFlag("cfguard-mechanism")))
+ MechanismOverride =
+ static_cast<ControlFlowGuardMechanism>(CI->getZExtValue());
+ switch (MechanismOverride) {
+ case ControlFlowGuardMechanism::ForceCheck:
+ GuardMechanism = Mechanism::Check;
+ break;
+ case ControlFlowGuardMechanism::ForceDispatch:
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/176276
More information about the cfe-commits
mailing list