52#define DEBUG_TYPE "shadow-stack-gc-lowering"
56class ShadowStackGCLoweringImpl {
65 std::vector<std::pair<CallInst *, AllocaInst *>> Roots;
69 std::vector<std::pair<uint64_t, uint64_t>> RootOffsets;
72 ShadowStackGCLoweringImpl() =
default;
74 bool doInitialization(
Module &M);
78 bool IsNullValue(
Value *V);
80 std::pair<uint64_t, Align> ComputeFrameLayout(
Function &
F);
85 ShadowStackGCLoweringImpl Impl;
90 ShadowStackGCLowering();
92 bool doInitialization(
Module &M)
override {
return Impl.doInitialization(M); }
97 std::optional<DomTreeUpdater> DTU;
98 if (
auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
99 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
100 return Impl.runOnFunction(
F, DTU ? &*DTU :
nullptr);
109 if (!Map.contains(
"shadow-stack"))
112 ShadowStackGCLoweringImpl Impl;
113 bool Changed = Impl.doInitialization(M);
119 Changed |= Impl.runOnFunction(
F, DT ? &DTU :
nullptr);
129char ShadowStackGCLowering::ID = 0;
133 "Shadow Stack GC Lowering",
false,
false)
139ShadowStackGCLowering::ShadowStackGCLowering() :
FunctionPass(ID) {}
147 unsigned NumMeta = 0;
149 for (
unsigned I = 0;
I != Roots.size(); ++
I) {
151 if (!
C->isNullValue())
160 ConstantInt::get(Int32Ty, FrameSizeInPtrs,
false),
161 ConstantInt::get(Int32Ty, NumMeta,
false),
188 "__gc_" +
F.getName());
191std::pair<uint64_t, Align>
192ShadowStackGCLoweringImpl::ComputeFrameLayout(
Function &
F) {
198 Align PtrAlign =
DL.getPointerABIAlignment(0);
201 Align MaxAlign = PtrAlign;
208 for (
const std::pair<CallInst *, AllocaInst *> &Root : Roots) {
211 if (!RootSize || !RootSize->isFixed())
213 "Intrinsic::gcroot requires a fixed size stack object");
216 MaxAlign = std::max(MaxAlign, RootAlign);
222 RootOffsets.push_back({AlignedOffset,
Size});
228 return {FrameSize, MaxAlign};
233bool ShadowStackGCLoweringImpl::doInitialization(
Module &M) {
236 if (
F.hasGC() &&
F.getGC() ==
"shadow-stack") {
249 std::vector<Type *> EltTys;
261 Head =
M.getGlobalVariable(
"llvm_gc_root_chain");
268 }
else if (Head->hasExternalLinkage() && Head->isDeclaration()) {
276bool ShadowStackGCLoweringImpl::IsNullValue(
Value *V) {
278 return C->isNullValue();
282void ShadowStackGCLoweringImpl::CollectRoots(
Function &
F) {
283 assert(Roots.empty() &&
"Not cleaned up?");
290 if (
Function *
F = CI->getCalledFunction())
291 if (
F->getIntrinsicID() == Intrinsic::gcroot) {
292 std::pair<CallInst *, AllocaInst *> Pair = std::make_pair(
295 if (IsNullValue(CI->getArgOperand(1)))
296 Roots.push_back(Pair);
303 Roots.insert(Roots.begin(), MetaRoots.
begin(), MetaRoots.
end());
307bool ShadowStackGCLoweringImpl::runOnFunction(
Function &
F,
310 if (!
F.hasGC() ||
F.getGC() !=
"shadow-stack")
325 auto [FrameSize, FrameAlign] = ComputeFrameLayout(
F);
329 Value *FrameMap = GetFrameMap(
F, FrameSize / PtrSize - 2);
335 AllocaInst *StackEntry = AtEntry.CreateAlloca(
339 AtEntry.SetInsertPointPastAllocas(&
F);
340 IP = AtEntry.GetInsertPoint();
344 AtEntry.CreateLoad(AtEntry.getPtrTy(), Head,
"gc_currhead");
347 Value *EntryMapPtr = AtEntry.CreatePtrAdd(
348 StackEntry, AtEntry.getInt64(PtrSize),
"gc_frame.map");
349 AtEntry.CreateStore(FrameMap, EntryMapPtr);
354 assert(RootOffsets.size() == Roots.size());
355 for (
unsigned I = 0,
E = Roots.size();
I !=
E; ++
I) {
356 auto [RootOffset, RootSize] = RootOffsets[
I];
359 if (RootOffset > LastEnd) {
361 AtEntry.CreatePtrAdd(StackEntry, AtEntry.getInt64(LastEnd));
362 AtEntry.CreateMemSet(PaddingPtr, AtEntry.getInt8(0), RootOffset - LastEnd,
367 Value *SlotPtr = AtEntry.CreatePtrAdd(
368 StackEntry, AtEntry.getInt64(RootOffset),
"gc_root");
375 LastEnd = RootOffset + RootSize;
379 if (FrameSize > LastEnd) {
381 AtEntry.CreatePtrAdd(StackEntry, AtEntry.getInt64(LastEnd));
382 AtEntry.CreateMemSet(PaddingPtr, AtEntry.getInt8(0), FrameSize - LastEnd,
392 AtEntry.SetInsertPoint(IP->getParent(), IP);
396 AtEntry.CreateStore(CurrentHead, StackEntry);
399 AtEntry.CreateStore(StackEntry, Head);
408 AtExit->CreateLoad(AtExit->getPtrTy(), StackEntry,
"gc_savedhead");
409 AtExit->CreateStore(SavedHead, Head);
415 for (std::pair<CallInst *, AllocaInst *> &Root : Roots) {
416 Root.first->eraseFromParent();
417 Root.second->eraseFromParent();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
an instruction to allocate memory on the stack
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
void setAlignment(Align Align)
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM Basic Block Representation.
InstListType::iterator iterator
Instruction iterators...
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
EscapeEnumerator - This is a little algorithm to find all escape points from a function so that "fina...
FunctionPass class - This class is used to implement most global optimizations.
An analysis pass which caches information about the entire Module.
@ InternalLinkage
Rename collisions when linking (static functions).
@ LinkOnceAnyLinkage
Keep one copy of function when linking (inline)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
A Module instance is used to store all the information related to an LLVM module.
Class to represent pointers.
static PointerType * getUnqual(LLVMContext &C)
This constructs an opaque pointer to an object in the default address space (address space zero).
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Class to represent struct types.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
std::string utostr(uint64_t X, bool isNeg=false)
LLVM_ABI char & ShadowStackGCLoweringID
ShadowStackGCLowering - Implements the custom lowering mechanism used by the shadow stack GC.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
This struct is a compact representation of a valid (non-zero power of two) alignment.