Skip to content

Commit 27259f1

Browse files
authored
[CodeGen] Port CFGuard to new pass manager (#75146)
Port `CFGuard` to new pass manager, add a pass parameter to choose guard mechanism.
1 parent 19fff85 commit 27259f1

File tree

7 files changed

+89
-39
lines changed

7 files changed

+89
-39
lines changed

llvm/include/llvm/CodeGen/CodeGenPassBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "llvm/Support/ErrorHandling.h"
4949
#include "llvm/Target/CGPassBuilderOption.h"
5050
#include "llvm/Target/TargetMachine.h"
51+
#include "llvm/Transforms/CFGuard.h"
5152
#include "llvm/Transforms/Scalar/ConstantHoisting.h"
5253
#include "llvm/Transforms/Scalar/LoopPassManager.h"
5354
#include "llvm/Transforms/Scalar/LoopStrengthReduce.h"

llvm/include/llvm/CodeGen/MachinePassRegistry.def

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ FUNCTION_ANALYSIS("targetir", TargetIRAnalysis,
3838
#define FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)
3939
#endif
4040
FUNCTION_PASS("callbrprepare", CallBrPreparePass, ())
41+
FUNCTION_PASS("cfguard", CFGuardPass, ())
4142
FUNCTION_PASS("consthoist", ConstantHoistingPass, ())
4243
FUNCTION_PASS("dwarf-eh-prepare", DwarfEHPreparePass, (TM))
4344
FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass, (false))
@@ -124,8 +125,6 @@ MACHINE_FUNCTION_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis,
124125
#define DUMMY_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)
125126
#endif
126127
DUMMY_FUNCTION_PASS("atomic-expand", AtomicExpandPass, ())
127-
DUMMY_FUNCTION_PASS("cfguard-check", CFGuardCheckPass, ())
128-
DUMMY_FUNCTION_PASS("cfguard-dispatch", CFGuardDispatchPass, ())
129128
DUMMY_FUNCTION_PASS("codegenprepare", CodeGenPreparePass, ())
130129
DUMMY_FUNCTION_PASS("expandmemcmp", ExpandMemCmpPass, ())
131130
DUMMY_FUNCTION_PASS("gc-lowering", GCLoweringPass, ())

llvm/include/llvm/Transforms/CFGuard.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,23 @@
1111
#ifndef LLVM_TRANSFORMS_CFGUARD_H
1212
#define LLVM_TRANSFORMS_CFGUARD_H
1313

14+
#include "llvm/IR/PassManager.h"
15+
1416
namespace llvm {
1517

1618
class FunctionPass;
1719

20+
class CFGuardPass : public PassInfoMixin<CFGuardPass> {
21+
public:
22+
enum class Mechanism { Check, Dispatch };
23+
24+
CFGuardPass(Mechanism M = Mechanism::Check) : GuardMechanism(M) {}
25+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
26+
27+
private:
28+
Mechanism GuardMechanism;
29+
};
30+
1831
/// Insert Control FLow Guard checks on indirect function calls.
1932
FunctionPass *createCFGuardCheckPass();
2033

llvm/lib/Passes/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_llvm_component_library(LLVMPasses
1616
LINK_COMPONENTS
1717
AggressiveInstCombine
1818
Analysis
19+
CFGuard
1920
CodeGen
2021
Core
2122
Coroutines

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#include "llvm/Support/Regex.h"
101101
#include "llvm/Target/TargetMachine.h"
102102
#include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h"
103+
#include "llvm/Transforms/CFGuard.h"
103104
#include "llvm/Transforms/Coroutines/CoroCleanup.h"
104105
#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h"
105106
#include "llvm/Transforms/Coroutines/CoroEarly.h"
@@ -738,6 +739,26 @@ Expected<bool> parsePostOrderFunctionAttrsPassOptions(StringRef Params) {
738739
"PostOrderFunctionAttrs");
739740
}
740741

742+
Expected<CFGuardPass::Mechanism> parseCFGuardPassOptions(StringRef Params) {
743+
if (Params.empty())
744+
return CFGuardPass::Mechanism::Check;
745+
746+
auto [Param, RHS] = Params.split(';');
747+
if (!RHS.empty())
748+
return make_error<StringError>(
749+
formatv("too many CFGuardPass parameters '{0}' ", Params).str(),
750+
inconvertibleErrorCode());
751+
752+
if (Param == "check")
753+
return CFGuardPass::Mechanism::Check;
754+
if (Param == "dispatch")
755+
return CFGuardPass::Mechanism::Dispatch;
756+
757+
return make_error<StringError>(
758+
formatv("invalid CFGuardPass mechanism: '{0}' ", Param).str(),
759+
inconvertibleErrorCode());
760+
}
761+
741762
Expected<bool> parseEarlyCSEPassOptions(StringRef Params) {
742763
return parseSinglePassOption(Params, "memssa", "EarlyCSE");
743764
}

llvm/lib/Passes/PassRegistry.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,10 @@ FUNCTION_PASS("wasm-eh-prepare", WasmEHPreparePass())
433433
#ifndef FUNCTION_PASS_WITH_PARAMS
434434
#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)
435435
#endif
436+
FUNCTION_PASS_WITH_PARAMS(
437+
"cfguard", "CFGuardPass",
438+
[](CFGuardPass::Mechanism M) { return CFGuardPass(M); },
439+
parseCFGuardPassOptions, "check;dispatch")
436440
FUNCTION_PASS_WITH_PARAMS(
437441
"early-cse", "EarlyCSEPass",
438442
[](bool UseMemorySSA) { return EarlyCSEPass(UseMemorySSA); },

llvm/lib/Transforms/CFGuard/CFGuard.cpp

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,22 @@ namespace {
3434

3535
/// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes.
3636
/// These checks ensure that the target address corresponds to the start of an
37-
/// address-taken function. X86_64 targets use the CF_Dispatch mechanism. X86,
38-
/// ARM, and AArch64 targets use the CF_Check machanism.
39-
class CFGuard : public FunctionPass {
37+
/// address-taken function. X86_64 targets use the Mechanism::Dispatch
38+
/// mechanism. X86, ARM, and AArch64 targets use the Mechanism::Check machanism.
39+
class CFGuardImpl {
4040
public:
41-
static char ID;
42-
43-
enum Mechanism { CF_Check, CF_Dispatch };
44-
45-
// Default constructor required for the INITIALIZE_PASS macro.
46-
CFGuard() : FunctionPass(ID) {
47-
initializeCFGuardPass(*PassRegistry::getPassRegistry());
48-
// By default, use the guard check mechanism.
49-
GuardMechanism = CF_Check;
50-
}
51-
52-
// Recommended constructor used to specify the type of guard mechanism.
53-
CFGuard(Mechanism Var) : FunctionPass(ID) {
54-
initializeCFGuardPass(*PassRegistry::getPassRegistry());
55-
GuardMechanism = Var;
41+
using Mechanism = CFGuardPass::Mechanism;
42+
43+
CFGuardImpl(Mechanism M) : GuardMechanism(M) {
44+
// Get or insert the guard check or dispatch global symbols.
45+
switch (GuardMechanism) {
46+
case Mechanism::Check:
47+
GuardFnName = "__guard_check_icall_fptr";
48+
break;
49+
case Mechanism::Dispatch:
50+
GuardFnName = "__guard_dispatch_icall_fptr";
51+
break;
52+
}
5653
}
5754

5855
/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
@@ -141,21 +138,37 @@ class CFGuard : public FunctionPass {
141138
/// \param CB indirect call to instrument.
142139
void insertCFGuardDispatch(CallBase *CB);
143140

144-
bool doInitialization(Module &M) override;
145-
bool runOnFunction(Function &F) override;
141+
bool doInitialization(Module &M);
142+
bool runOnFunction(Function &F);
146143

147144
private:
148145
// Only add checks if the module has the cfguard=2 flag.
149146
int cfguard_module_flag = 0;
150-
Mechanism GuardMechanism = CF_Check;
147+
StringRef GuardFnName;
148+
Mechanism GuardMechanism = Mechanism::Check;
151149
FunctionType *GuardFnType = nullptr;
152150
PointerType *GuardFnPtrType = nullptr;
153151
Constant *GuardFnGlobal = nullptr;
154152
};
155153

154+
class CFGuard : public FunctionPass {
155+
CFGuardImpl Impl;
156+
157+
public:
158+
static char ID;
159+
160+
// Default constructor required for the INITIALIZE_PASS macro.
161+
CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {
162+
initializeCFGuardPass(*PassRegistry::getPassRegistry());
163+
}
164+
165+
bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
166+
bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
167+
};
168+
156169
} // end anonymous namespace
157170

158-
void CFGuard::insertCFGuardCheck(CallBase *CB) {
171+
void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {
159172

160173
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
161174
"Only applicable for Windows targets");
@@ -184,7 +197,7 @@ void CFGuard::insertCFGuardCheck(CallBase *CB) {
184197
GuardCheck->setCallingConv(CallingConv::CFGuard_Check);
185198
}
186199

187-
void CFGuard::insertCFGuardDispatch(CallBase *CB) {
200+
void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {
188201

189202
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
190203
"Only applicable for Windows targets");
@@ -218,7 +231,7 @@ void CFGuard::insertCFGuardDispatch(CallBase *CB) {
218231
CB->eraseFromParent();
219232
}
220233

221-
bool CFGuard::doInitialization(Module &M) {
234+
bool CFGuardImpl::doInitialization(Module &M) {
222235

223236
// Check if this module has the cfguard flag and read its value.
224237
if (auto *MD =
@@ -235,15 +248,6 @@ bool CFGuard::doInitialization(Module &M) {
235248
{PointerType::getUnqual(M.getContext())}, false);
236249
GuardFnPtrType = PointerType::get(GuardFnType, 0);
237250

238-
// Get or insert the guard check or dispatch global symbols.
239-
llvm::StringRef GuardFnName;
240-
if (GuardMechanism == CF_Check) {
241-
GuardFnName = "__guard_check_icall_fptr";
242-
} else if (GuardMechanism == CF_Dispatch) {
243-
GuardFnName = "__guard_dispatch_icall_fptr";
244-
} else {
245-
assert(false && "Invalid CFGuard mechanism");
246-
}
247251
GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {
248252
auto *Var = new GlobalVariable(M, GuardFnPtrType, false,
249253
GlobalVariable::ExternalLinkage, nullptr,
@@ -255,7 +259,7 @@ bool CFGuard::doInitialization(Module &M) {
255259
return true;
256260
}
257261

258-
bool CFGuard::runOnFunction(Function &F) {
262+
bool CFGuardImpl::runOnFunction(Function &F) {
259263

260264
// Skip modules for which CFGuard checks have been disabled.
261265
if (cfguard_module_flag != 2)
@@ -283,7 +287,7 @@ bool CFGuard::runOnFunction(Function &F) {
283287
}
284288

285289
// For each indirect call/invoke, add the appropriate dispatch or check.
286-
if (GuardMechanism == CF_Dispatch) {
290+
if (GuardMechanism == Mechanism::Dispatch) {
287291
for (CallBase *CB : IndirectCalls) {
288292
insertCFGuardDispatch(CB);
289293
}
@@ -296,13 +300,20 @@ bool CFGuard::runOnFunction(Function &F) {
296300
return true;
297301
}
298302

303+
PreservedAnalyses CFGuardPass::run(Function &F, FunctionAnalysisManager &FAM) {
304+
CFGuardImpl Impl(GuardMechanism);
305+
bool Changed = Impl.doInitialization(*F.getParent());
306+
Changed |= Impl.runOnFunction(F);
307+
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
308+
}
309+
299310
char CFGuard::ID = 0;
300311
INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false)
301312

302313
FunctionPass *llvm::createCFGuardCheckPass() {
303-
return new CFGuard(CFGuard::CF_Check);
314+
return new CFGuard(CFGuardPass::Mechanism::Check);
304315
}
305316

306317
FunctionPass *llvm::createCFGuardDispatchPass() {
307-
return new CFGuard(CFGuard::CF_Dispatch);
318+
return new CFGuard(CFGuardPass::Mechanism::Dispatch);
308319
}

0 commit comments

Comments
 (0)