[CodeGen] Port CFGuard to new pass manager (#75146)
Port `CFGuard` to new pass manager, add a pass parameter to choose guard mechanism.
This commit is contained in:
@@ -48,6 +48,7 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Target/CGPassBuilderOption.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Transforms/CFGuard.h"
|
||||
#include "llvm/Transforms/Scalar/ConstantHoisting.h"
|
||||
#include "llvm/Transforms/Scalar/LoopPassManager.h"
|
||||
#include "llvm/Transforms/Scalar/LoopStrengthReduce.h"
|
||||
|
||||
@@ -38,6 +38,7 @@ FUNCTION_ANALYSIS("targetir", TargetIRAnalysis,
|
||||
#define FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)
|
||||
#endif
|
||||
FUNCTION_PASS("callbrprepare", CallBrPreparePass, ())
|
||||
FUNCTION_PASS("cfguard", CFGuardPass, ())
|
||||
FUNCTION_PASS("consthoist", ConstantHoistingPass, ())
|
||||
FUNCTION_PASS("dwarf-eh-prepare", DwarfEHPreparePass, (TM))
|
||||
FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass, (false))
|
||||
@@ -124,8 +125,6 @@ MACHINE_FUNCTION_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis,
|
||||
#define DUMMY_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)
|
||||
#endif
|
||||
DUMMY_FUNCTION_PASS("atomic-expand", AtomicExpandPass, ())
|
||||
DUMMY_FUNCTION_PASS("cfguard-check", CFGuardCheckPass, ())
|
||||
DUMMY_FUNCTION_PASS("cfguard-dispatch", CFGuardDispatchPass, ())
|
||||
DUMMY_FUNCTION_PASS("codegenprepare", CodeGenPreparePass, ())
|
||||
DUMMY_FUNCTION_PASS("expandmemcmp", ExpandMemCmpPass, ())
|
||||
DUMMY_FUNCTION_PASS("gc-lowering", GCLoweringPass, ())
|
||||
|
||||
@@ -11,10 +11,23 @@
|
||||
#ifndef LLVM_TRANSFORMS_CFGUARD_H
|
||||
#define LLVM_TRANSFORMS_CFGUARD_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class FunctionPass;
|
||||
|
||||
class CFGuardPass : public PassInfoMixin<CFGuardPass> {
|
||||
public:
|
||||
enum class Mechanism { Check, Dispatch };
|
||||
|
||||
CFGuardPass(Mechanism M = Mechanism::Check) : GuardMechanism(M) {}
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
|
||||
|
||||
private:
|
||||
Mechanism GuardMechanism;
|
||||
};
|
||||
|
||||
/// Insert Control FLow Guard checks on indirect function calls.
|
||||
FunctionPass *createCFGuardCheckPass();
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ add_llvm_component_library(LLVMPasses
|
||||
LINK_COMPONENTS
|
||||
AggressiveInstCombine
|
||||
Analysis
|
||||
CFGuard
|
||||
CodeGen
|
||||
Core
|
||||
Coroutines
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h"
|
||||
#include "llvm/Transforms/CFGuard.h"
|
||||
#include "llvm/Transforms/Coroutines/CoroCleanup.h"
|
||||
#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h"
|
||||
#include "llvm/Transforms/Coroutines/CoroEarly.h"
|
||||
@@ -738,6 +739,26 @@ Expected<bool> parsePostOrderFunctionAttrsPassOptions(StringRef Params) {
|
||||
"PostOrderFunctionAttrs");
|
||||
}
|
||||
|
||||
Expected<CFGuardPass::Mechanism> parseCFGuardPassOptions(StringRef Params) {
|
||||
if (Params.empty())
|
||||
return CFGuardPass::Mechanism::Check;
|
||||
|
||||
auto [Param, RHS] = Params.split(';');
|
||||
if (!RHS.empty())
|
||||
return make_error<StringError>(
|
||||
formatv("too many CFGuardPass parameters '{0}' ", Params).str(),
|
||||
inconvertibleErrorCode());
|
||||
|
||||
if (Param == "check")
|
||||
return CFGuardPass::Mechanism::Check;
|
||||
if (Param == "dispatch")
|
||||
return CFGuardPass::Mechanism::Dispatch;
|
||||
|
||||
return make_error<StringError>(
|
||||
formatv("invalid CFGuardPass mechanism: '{0}' ", Param).str(),
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
Expected<bool> parseEarlyCSEPassOptions(StringRef Params) {
|
||||
return parseSinglePassOption(Params, "memssa", "EarlyCSE");
|
||||
}
|
||||
|
||||
@@ -433,6 +433,10 @@ FUNCTION_PASS("wasm-eh-prepare", WasmEHPreparePass())
|
||||
#ifndef FUNCTION_PASS_WITH_PARAMS
|
||||
#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)
|
||||
#endif
|
||||
FUNCTION_PASS_WITH_PARAMS(
|
||||
"cfguard", "CFGuardPass",
|
||||
[](CFGuardPass::Mechanism M) { return CFGuardPass(M); },
|
||||
parseCFGuardPassOptions, "check;dispatch")
|
||||
FUNCTION_PASS_WITH_PARAMS(
|
||||
"early-cse", "EarlyCSEPass",
|
||||
[](bool UseMemorySSA) { return EarlyCSEPass(UseMemorySSA); },
|
||||
|
||||
@@ -34,25 +34,22 @@ 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 CF_Dispatch mechanism. X86,
|
||||
/// ARM, and AArch64 targets use the CF_Check machanism.
|
||||
class CFGuard : public FunctionPass {
|
||||
/// address-taken function. X86_64 targets use the Mechanism::Dispatch
|
||||
/// mechanism. X86, ARM, and AArch64 targets use the Mechanism::Check machanism.
|
||||
class CFGuardImpl {
|
||||
public:
|
||||
static char ID;
|
||||
using Mechanism = CFGuardPass::Mechanism;
|
||||
|
||||
enum Mechanism { CF_Check, CF_Dispatch };
|
||||
|
||||
// Default constructor required for the INITIALIZE_PASS macro.
|
||||
CFGuard() : FunctionPass(ID) {
|
||||
initializeCFGuardPass(*PassRegistry::getPassRegistry());
|
||||
// By default, use the guard check mechanism.
|
||||
GuardMechanism = CF_Check;
|
||||
}
|
||||
|
||||
// Recommended constructor used to specify the type of guard mechanism.
|
||||
CFGuard(Mechanism Var) : FunctionPass(ID) {
|
||||
initializeCFGuardPass(*PassRegistry::getPassRegistry());
|
||||
GuardMechanism = Var;
|
||||
CFGuardImpl(Mechanism M) : GuardMechanism(M) {
|
||||
// Get or insert the guard check or dispatch global symbols.
|
||||
switch (GuardMechanism) {
|
||||
case Mechanism::Check:
|
||||
GuardFnName = "__guard_check_icall_fptr";
|
||||
break;
|
||||
case Mechanism::Dispatch:
|
||||
GuardFnName = "__guard_dispatch_icall_fptr";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
|
||||
@@ -141,21 +138,37 @@ public:
|
||||
/// \param CB indirect call to instrument.
|
||||
void insertCFGuardDispatch(CallBase *CB);
|
||||
|
||||
bool doInitialization(Module &M) override;
|
||||
bool runOnFunction(Function &F) override;
|
||||
bool doInitialization(Module &M);
|
||||
bool runOnFunction(Function &F);
|
||||
|
||||
private:
|
||||
// Only add checks if the module has the cfguard=2 flag.
|
||||
int cfguard_module_flag = 0;
|
||||
Mechanism GuardMechanism = CF_Check;
|
||||
StringRef GuardFnName;
|
||||
Mechanism GuardMechanism = Mechanism::Check;
|
||||
FunctionType *GuardFnType = nullptr;
|
||||
PointerType *GuardFnPtrType = nullptr;
|
||||
Constant *GuardFnGlobal = nullptr;
|
||||
};
|
||||
|
||||
class CFGuard : public FunctionPass {
|
||||
CFGuardImpl Impl;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
// Default constructor required for the INITIALIZE_PASS macro.
|
||||
CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {
|
||||
initializeCFGuardPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
|
||||
bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void CFGuard::insertCFGuardCheck(CallBase *CB) {
|
||||
void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {
|
||||
|
||||
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
|
||||
"Only applicable for Windows targets");
|
||||
@@ -184,7 +197,7 @@ void CFGuard::insertCFGuardCheck(CallBase *CB) {
|
||||
GuardCheck->setCallingConv(CallingConv::CFGuard_Check);
|
||||
}
|
||||
|
||||
void CFGuard::insertCFGuardDispatch(CallBase *CB) {
|
||||
void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {
|
||||
|
||||
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
|
||||
"Only applicable for Windows targets");
|
||||
@@ -218,7 +231,7 @@ void CFGuard::insertCFGuardDispatch(CallBase *CB) {
|
||||
CB->eraseFromParent();
|
||||
}
|
||||
|
||||
bool CFGuard::doInitialization(Module &M) {
|
||||
bool CFGuardImpl::doInitialization(Module &M) {
|
||||
|
||||
// Check if this module has the cfguard flag and read its value.
|
||||
if (auto *MD =
|
||||
@@ -235,15 +248,6 @@ bool CFGuard::doInitialization(Module &M) {
|
||||
{PointerType::getUnqual(M.getContext())}, false);
|
||||
GuardFnPtrType = PointerType::get(GuardFnType, 0);
|
||||
|
||||
// Get or insert the guard check or dispatch global symbols.
|
||||
llvm::StringRef GuardFnName;
|
||||
if (GuardMechanism == CF_Check) {
|
||||
GuardFnName = "__guard_check_icall_fptr";
|
||||
} else if (GuardMechanism == CF_Dispatch) {
|
||||
GuardFnName = "__guard_dispatch_icall_fptr";
|
||||
} else {
|
||||
assert(false && "Invalid CFGuard mechanism");
|
||||
}
|
||||
GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {
|
||||
auto *Var = new GlobalVariable(M, GuardFnPtrType, false,
|
||||
GlobalVariable::ExternalLinkage, nullptr,
|
||||
@@ -255,7 +259,7 @@ bool CFGuard::doInitialization(Module &M) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFGuard::runOnFunction(Function &F) {
|
||||
bool CFGuardImpl::runOnFunction(Function &F) {
|
||||
|
||||
// Skip modules for which CFGuard checks have been disabled.
|
||||
if (cfguard_module_flag != 2)
|
||||
@@ -283,7 +287,7 @@ bool CFGuard::runOnFunction(Function &F) {
|
||||
}
|
||||
|
||||
// For each indirect call/invoke, add the appropriate dispatch or check.
|
||||
if (GuardMechanism == CF_Dispatch) {
|
||||
if (GuardMechanism == Mechanism::Dispatch) {
|
||||
for (CallBase *CB : IndirectCalls) {
|
||||
insertCFGuardDispatch(CB);
|
||||
}
|
||||
@@ -296,13 +300,20 @@ bool CFGuard::runOnFunction(Function &F) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PreservedAnalyses CFGuardPass::run(Function &F, FunctionAnalysisManager &FAM) {
|
||||
CFGuardImpl Impl(GuardMechanism);
|
||||
bool Changed = Impl.doInitialization(*F.getParent());
|
||||
Changed |= Impl.runOnFunction(F);
|
||||
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
char CFGuard::ID = 0;
|
||||
INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false)
|
||||
|
||||
FunctionPass *llvm::createCFGuardCheckPass() {
|
||||
return new CFGuard(CFGuard::CF_Check);
|
||||
return new CFGuard(CFGuardPass::Mechanism::Check);
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createCFGuardDispatchPass() {
|
||||
return new CFGuard(CFGuard::CF_Dispatch);
|
||||
return new CFGuard(CFGuardPass::Mechanism::Dispatch);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user