LLVM: lib/CodeGen/ShadowStackGCLowering.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
43#include
44#include
45#include
46#include
47
48using namespace llvm;
49
50#define DEBUG_TYPE "shadow-stack-gc-lowering"
51
52namespace {
53
54class ShadowStackGCLoweringImpl {
55
56
58
59
62
63
64
65 std::vector<std::pair<CallInst *, AllocaInst *>> Roots;
66
67public:
68 ShadowStackGCLoweringImpl() = default;
69
70 bool doInitialization(Module &M);
72
73private:
74 bool IsNullValue(Value *V);
78
80 Type *Ty, Value *BasePtr, int Idx1,
81 const char *Name);
83 Type *Ty, Value *BasePtr, int Idx1, int Idx2,
84 const char *Name);
85};
86
87class ShadowStackGCLowering : public FunctionPass {
88 ShadowStackGCLoweringImpl Impl;
89
90public:
91 static char ID;
92
93 ShadowStackGCLowering();
94
98 }
100 std::optional DTU;
101 if (auto *DTWP = getAnalysisIfAvailable())
102 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
103 return Impl.runOnFunction(F, DTU ? &*DTU : nullptr);
104 }
105};
106
107}
108
112 if (Map.StrategyMap.contains("shadow-stack"))
114
115 ShadowStackGCLoweringImpl Impl;
116 bool Changed = Impl.doInitialization(M);
117 for (auto &F : M) {
118 auto &FAM =
121 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
122 Changed |= Impl.runOnFunction(F, DT ? &DTU : nullptr);
123 }
124
125 if (!Changed)
129 return PA;
130}
131
132char ShadowStackGCLowering::ID = 0;
134
136 "Shadow Stack GC Lowering", false, false)
141
143
144ShadowStackGCLowering::ShadowStackGCLowering() : FunctionPass(ID) {
146}
147
149
150 Type *VoidPtr = PointerType::getUnqual(F.getContext());
151
152
153 unsigned NumMeta = 0;
155 for (unsigned I = 0; I != Roots.size(); ++I) {
156 Constant *C = cast(Roots[I].first->getArgOperand(1));
157 if (->isNullValue())
158 NumMeta = I + 1;
160 }
162
164
166 ConstantInt::get(Int32Ty, Roots.size(), false),
167 ConstantInt::get(Int32Ty, NumMeta, false),
168 };
169
170 Constant *DescriptorElts[] = {
173
174 Type *EltTys[] = {DescriptorElts[0]->getType(), DescriptorElts[1]->getType()};
176
178
179
180
181
182
183
184
185
186
187
188
189
190
191
193 GlobalVariable::InternalLinkage, FrameMap,
194 "__gc_" + F.getName());
195
200}
201
202Type *ShadowStackGCLoweringImpl::GetConcreteStackEntryType(Function &F) {
203
204 std::vector<Type *> EltTys;
205 EltTys.push_back(StackEntryTy);
206 for (const std::pair<CallInst *, AllocaInst *> &Root : Roots)
207 EltTys.push_back(Root.second->getAllocatedType());
208
209 return StructType::create(EltTys, ("gc_stackentry." + F.getName()).str());
210}
211
212
213
214bool ShadowStackGCLoweringImpl::doInitialization(Module &M) {
217 if (F.hasGC() && F.getGC() == "shadow-stack") {
219 break;
220 }
221 }
222 if (!Active)
223 return false;
224
225
226
227
228
229
230 std::vector<Type *> EltTys;
231
233
236 PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);
237
238
239
240
241
242
243
244 PointerType *StackEntryPtrTy = PointerType::getUnqual(M.getContext());
245
246 EltTys.clear();
247 EltTys.push_back(StackEntryPtrTy);
248 EltTys.push_back(FrameMapPtrTy);
250
251
252 Head = M.getGlobalVariable("llvm_gc_root_chain");
253 if (!Head) {
254
255
259 } else if (Head->hasExternalLinkage() && Head->isDeclaration()) {
262 }
263
264 return true;
265}
266
267bool ShadowStackGCLoweringImpl::IsNullValue(Value *V) {
268 if (Constant *C = dyn_cast(V))
269 return C->isNullValue();
270 return false;
271}
272
273void ShadowStackGCLoweringImpl::CollectRoots(Function &F) {
274
275
276
277
278 assert(Roots.empty() && "Not cleaned up?");
279
281
285 if (Function *F = CI->getCalledFunction())
286 if (F->getIntrinsicID() == Intrinsic::gcroot) {
287 std::pair<CallInst *, AllocaInst *> Pair = std::make_pair(
288 CI,
289 cast(CI->getArgOperand(0)->stripPointerCasts()));
290 if (IsNullValue(CI->getArgOperand(1)))
291 Roots.push_back(Pair);
292 else
294 }
295
296
297
298 Roots.insert(Roots.begin(), MetaRoots.begin(), MetaRoots.end());
299}
300
304 int Idx2, const char *Name) {
308 Value *Val = B.CreateGEP(Ty, BasePtr, Indices, Name);
309
310 assert(isa(Val) && "Unexpected folded constant");
311
312 return dyn_cast(Val);
313}
314
319 const char *Name) {
322 Value *Val = B.CreateGEP(Ty, BasePtr, Indices, Name);
323
324 assert(isa(Val) && "Unexpected folded constant");
325
326 return dyn_cast(Val);
327}
328
329
330bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
332
333 if (.hasGC() || F.getGC() != "shadow-stack")
334 return false;
335
337
338
339 CollectRoots(F);
340
341
342
343 if (Roots.empty())
344 return false;
345
346
347 Value *FrameMap = GetFrameMap(F);
348 Type *ConcreteStackEntryTy = GetConcreteStackEntryType(F);
349
350
352 IRBuilder<> AtEntry(IP->getParent(), IP);
353
355 AtEntry.CreateAlloca(ConcreteStackEntryTy, nullptr, "gc_frame");
356
357 AtEntry.SetInsertPointPastAllocas(&F);
358 IP = AtEntry.GetInsertPoint();
359
360
362 AtEntry.CreateLoad(AtEntry.getPtrTy(), Head, "gc_currhead");
363 Instruction *EntryMapPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
364 StackEntry, 0, 1, "gc_frame.map");
365 AtEntry.CreateStore(FrameMap, EntryMapPtr);
366
367
368 for (unsigned I = 0, E = Roots.size(); I != E; ++I) {
369
370 Value *SlotPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
371 StackEntry, 1 + I, "gc_root");
372
373
374 AllocaInst *OriginalAlloca = Roots[I].second;
375 SlotPtr->takeName(OriginalAlloca);
377 }
378
379
380
381
382
383 while (isa(IP))
384 ++IP;
385 AtEntry.SetInsertPoint(IP->getParent(), IP);
386
387
388 Instruction *EntryNextPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
389 StackEntry, 0, 0, "gc_frame.next");
390 Instruction *NewHeadVal = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
391 StackEntry, 0, "gc_newhead");
392 AtEntry.CreateStore(CurrentHead, EntryNextPtr);
393 AtEntry.CreateStore(NewHeadVal, Head);
394
395
396 EscapeEnumerator EE(F, "gc_cleanup", true, DTU);
397 while (IRBuilder<> *AtExit = EE.Next()) {
398
399
401 CreateGEP(Context, *AtExit, ConcreteStackEntryTy, StackEntry, 0, 0,
402 "gc_frame.next");
403 Value *SavedHead =
404 AtExit->CreateLoad(AtExit->getPtrTy(), EntryNextPtr2, "gc_savedhead");
405 AtExit->CreateStore(SavedHead, Head);
406 }
407
408
409
410
411 for (std::pair<CallInst *, AllocaInst *> &Root : Roots) {
412 Root.first->eraseFromParent();
413 Root.second->eraseFromParent();
414 }
415
416 Roots.clear();
417 return true;
418}
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
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)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
an instruction to allocate memory on the stack
A container for analyses that lazily runs them and caches their results.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
InstListType::iterator iterator
Instruction iterators...
static Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
static Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
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.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
An analysis pass which caches information about the entire Module.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
@ 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...
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
A Module instance is used to store all the information related to an LLVM module.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
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.
void preserve()
Mark an analysis as preserved.
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 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 IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void takeName(Value *V)
Transfer the name from V to this value.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
char & ShadowStackGCLoweringID
ShadowStackGCLowering - Implements the custom lowering mechanism used by the shadow stack GC.
void initializeShadowStackGCLoweringPass(PassRegistry &)
FunctionPass * createShadowStackGCLoweringPass()
ShadowStackGCLowering - Implements the custom lowering mechanism used by the shadow stack GC.