28 #define DEBUG_TYPE "shadowstackgc"
53 std::vector<std::pair<CallInst*,AllocaInst*> > Roots;
58 bool initializeCustomLowering(
Module &M);
62 bool IsNullValue(
Value *V);
68 int Idx1,
const char *
Name);
71 int Idx1,
int Idx2,
const char *Name);
77 X(
"shadow-stack",
"Very portable GC for uncooperative code generators");
88 class EscapeEnumerator {
90 const char *CleanupBBName;
98 EscapeEnumerator(
Function &
F,
const char *
N =
"cleanup")
99 : F(F), CleanupBBName(
N), State(0), Builder(F.getContext()) {}
113 while (StateBB != StateE) {
119 if (!isa<ReturnInst>(TI) && !isa<ResumeInst>(TI))
122 Builder.SetInsertPoint(TI->
getParent(), TI);
131 E =
F.end(); BB != E; ++BB)
133 EE = BB->end(); II != EE; ++II)
134 if (
CallInst *CI = dyn_cast<CallInst>(II))
135 if (!CI->getCalledFunction() ||
136 !CI->getCalledFunction()->getIntrinsicID())
149 getOrInsertFunction(
"__gcc_personality_v0",
160 for (
unsigned I = Calls.
size();
I != 0; ) {
161 CallInst *CI = cast<CallInst>(Calls[--
I]);
175 Args.
append(CS.arg_begin(), CS.arg_end());
186 Builder.SetInsertPoint(RI->
getParent(), RI);
197 ShadowStackGC::ShadowStackGC() : Head(0), StackEntryTy(0) {
207 unsigned NumMeta = 0;
209 for (
unsigned I = 0;
I != Roots.size(); ++
I) {
210 Constant *C = cast<Constant>(Roots[
I].first->getArgOperand(1));
213 Metadata.
push_back(ConstantExpr::getBitCast(C, VoidPtr));
220 ConstantInt::get(Int32Ty, Roots.size(),
false),
221 ConstantInt::get(Int32Ty, NumMeta,
false),
225 ConstantStruct::get(FrameMapTy, BaseElts),
226 ConstantArray::get(ArrayType::get(VoidPtr, NumMeta), Metadata)
232 Constant *FrameMap = ConstantStruct::get(STy, DescriptorElts);
248 GlobalVariable::InternalLinkage,
249 FrameMap,
"__gc_" + F.
getName());
252 ConstantInt::get(Type::getInt32Ty(F.
getContext()), 0),
253 ConstantInt::get(Type::getInt32Ty(F.
getContext()), 0)
255 return ConstantExpr::getGetElementPtr(GV, GEPIndices);
258 Type* ShadowStackGC::GetConcreteStackEntryType(
Function &F) {
260 std::vector<Type*> EltTys;
261 EltTys.push_back(StackEntryTy);
262 for (
size_t I = 0;
I != Roots.size();
I++)
263 EltTys.push_back(Roots[
I].second->getAllocatedType());
265 return StructType::create(EltTys,
"gc_stackentry."+F.
getName().
str());
270 bool ShadowStackGC::initializeCustomLowering(
Module &M) {
276 std::vector<Type*> EltTys;
278 EltTys.push_back(Type::getInt32Ty(M.
getContext()));
280 EltTys.push_back(Type::getInt32Ty(M.
getContext()));
281 FrameMapTy = StructType::create(EltTys,
"gc_map");
282 PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);
290 StackEntryTy = StructType::create(M.
getContext(),
"gc_stackentry");
293 EltTys.push_back(PointerType::getUnqual(StackEntryTy));
294 EltTys.push_back(FrameMapPtrTy);
295 StackEntryTy->setBody(EltTys);
296 PointerType *StackEntryPtrTy = PointerType::getUnqual(StackEntryTy);
304 GlobalValue::LinkOnceAnyLinkage,
305 Constant::getNullValue(StackEntryPtrTy),
306 "llvm_gc_root_chain");
307 }
else if (Head->hasExternalLinkage() && Head->isDeclaration()) {
308 Head->setInitializer(Constant::getNullValue(StackEntryPtrTy));
309 Head->setLinkage(GlobalValue::LinkOnceAnyLinkage);
315 bool ShadowStackGC::IsNullValue(
Value *V) {
316 if (
Constant *C = dyn_cast<Constant>(V))
321 void ShadowStackGC::CollectRoots(
Function &F) {
326 assert(Roots.empty() &&
"Not cleaned up?");
335 std::pair<CallInst*, AllocaInst*> Pair = std::make_pair(
338 Roots.push_back(Pair);
340 MetaRoots.push_back(Pair);
345 Roots.insert(Roots.begin(), MetaRoots.begin(), MetaRoots.end());
350 int Idx,
int Idx2,
const char *
Name) {
351 Value *Indices[] = { ConstantInt::get(Type::getInt32Ty(Context), 0),
352 ConstantInt::get(Type::getInt32Ty(Context), Idx),
353 ConstantInt::get(Type::getInt32Ty(Context), Idx2) };
356 assert(isa<GetElementPtrInst>(Val) &&
"Unexpected folded constant");
363 int Idx,
const char *Name) {
364 Value *Indices[] = { ConstantInt::get(Type::getInt32Ty(Context), 0),
365 ConstantInt::get(Type::getInt32Ty(Context), Idx) };
368 assert(isa<GetElementPtrInst>(Val) &&
"Unexpected folded constant");
374 bool ShadowStackGC::performCustomLowering(
Function &F) {
386 Value *FrameMap = GetFrameMap(F);
387 Type *ConcreteStackEntryTy = GetConcreteStackEntryType(F);
393 Instruction *StackEntry = AtEntry.CreateAlloca(ConcreteStackEntryTy, 0,
396 while (isa<AllocaInst>(IP)) ++IP;
397 AtEntry.SetInsertPoint(IP->getParent(), IP);
400 Instruction *CurrentHead = AtEntry.CreateLoad(Head,
"gc_currhead");
401 Instruction *EntryMapPtr = CreateGEP(Context, AtEntry, StackEntry,
403 AtEntry.CreateStore(FrameMap, EntryMapPtr);
406 for (
unsigned I = 0, E = Roots.size();
I != E; ++
I) {
408 Value *SlotPtr = CreateGEP(Context, AtEntry, StackEntry, 1 +
I,
"gc_root");
420 while (isa<StoreInst>(IP)) ++IP;
421 AtEntry.SetInsertPoint(IP->getParent(), IP);
424 Instruction *EntryNextPtr = CreateGEP(Context, AtEntry,
425 StackEntry,0,0,
"gc_frame.next");
426 Instruction *NewHeadVal = CreateGEP(Context, AtEntry,
427 StackEntry, 0,
"gc_newhead");
428 AtEntry.CreateStore(CurrentHead, EntryNextPtr);
429 AtEntry.CreateStore(NewHeadVal, Head);
432 EscapeEnumerator EE(F,
"gc_cleanup");
436 Instruction *EntryNextPtr2 = CreateGEP(Context, *AtExit, StackEntry, 0, 0,
438 Value *SavedHead = AtExit->CreateLoad(EntryNextPtr2,
"gc_savedhead");
439 AtExit->CreateStore(SavedHead, Head);
445 for (
unsigned I = 0, E = Roots.size();
I != E; ++
I) {
446 Roots[
I].first->eraseFromParent();
447 Roots[
I].second->eraseFromParent();
Value * CreateGEP(Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
const Value * getCalledValue() const
void setAttributes(const AttributeSet &Attrs)
void push_back(const T &Elt)
LLVMContext & getContext() const
The main container class for the LLVM Intermediate Representation.
enable_if_c<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
std::string str() const
str - Get the contents as an std::string.
const GlobalVariable * getGlobalVariable(StringRef Name, bool AllowInternal=false) const
StringRef getName() const
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
void setCleanup(bool V)
setCleanup - Indicate that this landingpad instruction is a cleanup.
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const
static LandingPadInst * Create(Type *RetTy, Value *PersonalityFn, unsigned NumReservedClauses, const Twine &NameStr="", Instruction *InsertBefore=0)
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
static std::string utostr(uint64_t X, bool isNeg=false)
void replaceAllUsesWith(Value *V)
LLVM Basic Block Representation.
unsigned getIntrinsicID() const LLVM_READONLY
LLVM Constant Representation.
static InvokeInst * Create(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef< Value * > Args, const Twine &NameStr="", Instruction *InsertBefore=0)
const InstListType & getInstList() const
Return the underlying instruction list container.
void append(in_iter in_start, in_iter in_end)
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
Value * stripPointerCasts()
Strips off any unneeded pointer casts, all-zero GEPs and aliases from the specified value...
Function * getCalledFunction() const
const BasicBlock & getEntryBlock() const
Value * getArgOperand(unsigned i) const
const AttributeSet & getAttributes() const
static IntegerType * getInt32Ty(LLVMContext &C)
TerminatorInst * getTerminator()
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=0, BasicBlock *InsertBefore=0)
Creates a new BasicBlock.
BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
LLVM Value Representation.
void setCallingConv(CallingConv::ID CC)
CallingConv::ID getCallingConv() const
NodeTy * remove(iterator &IT)
static ResumeInst * Create(Value *Exn, Instruction *InsertBefore=0)
static RegisterPass< NVPTXAllocaHoisting > X("alloca-hoisting","Hoisting alloca instructions in non-entry ""blocks to the entry block")
const BasicBlock * getParent() const
LLVMContext & getContext() const