StackProtector.cpp revision f7a0c7bf8bc8318ed28d889c9a56437ab3e91385
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//===-- StackProtector.cpp - Stack Protector Insertion --------------------===// 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// The LLVM Compiler Infrastructure 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// This file is distributed under the University of Illinois Open Source 69d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org// License. See LICENSE.TXT for details. 79d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org// 89d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org//===----------------------------------------------------------------------===// 9fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org// 10d537341e16524d1e22ac5e6c8b9c8f274ba1833crobertphillips// This pass inserts stack protectors into functions which need them. A variable 1169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com// with a random value in it is stored onto the stack before the local variables 129d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org// are allocated. Upon exiting the block, the stored value is checked. If it's 1381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com// changed, then there was some sort of violation and the program aborts. 14b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com// 15fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org//===----------------------------------------------------------------------===// 16181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com 171878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org#define DEBUG_TYPE "stack-protector" 181878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org#include "llvm/CodeGen/Passes.h" 1981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com#include "llvm/Attributes.h" 20181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com#include "llvm/Constants.h" 21181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com#include "llvm/DerivedTypes.h" 22383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Function.h" 23383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Instructions.h" 24383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Intrinsics.h" 25b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com#include "llvm/Module.h" 26383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Pass.h" 27383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Support/CommandLine.h" 28383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Target/TargetData.h" 29383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Target/TargetLowering.h" 30383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.comusing namespace llvm; 31181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com 3281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com// SSPBufferSize - The lower bound for a buffer to be considered for stack 33181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com// smashing protection. 34181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.comstatic cl::opt<unsigned> 35181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.comSSPBufferSize("stack-protector-buffer-size", cl::init(8), 36b5b3168a645802f66233234a06dd5a3764f18018bsalomon@google.com cl::desc("Lower bound for a buffer to be considered for " 374b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org "stack protection")); 389d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 39972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgnamespace { 4081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com class StackProtector : public FunctionPass { 41c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com /// TLI - Keep a pointer of a TargetLowering to consult for determining 42afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com /// target type sizes. 43c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com const TargetLowering *TLI; 44f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org 45c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com Function *F; 4681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com Module *M; 47c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com 489d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org /// InsertStackProtectors - Insert code into the prologue and epilogue of 499d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org /// the function. 509d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org /// 519d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org /// - The prologue code loads and stores the stack guard onto the stack. 529d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org /// - The epilogue checks the value stored in the prologue against the 539d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org /// original value. It calls __stack_chk_fail if they differ. 54e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com bool InsertStackProtectors(); 5561f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com 5661f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com /// CreateFailBB - Create a basic block to jump to when the stack protector 5761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com /// check fails. 5861f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com BasicBlock *CreateFailBB(); 5961f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com 6061f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com /// RequiresStackProtector - Check whether or not this function needs a 6161f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com /// stack protector based upon the stack protector level. 62972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org bool RequiresStackProtector() const; 639d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org public: 649d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org static char ID; // Pass identification, replacement for typeid. 659d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org StackProtector() : FunctionPass(&ID), TLI(0) {} 66972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org StackProtector(const TargetLowering *tli) 67972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org : FunctionPass(&ID), TLI(tli) {} 68972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org 6981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com virtual bool runOnFunction(Function &Fn); 70972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org }; 71c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com} // end anonymous namespace 729d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 739d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgchar StackProtector::ID = 0; 749d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgstatic RegisterPass<StackProtector> 759d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgX("stack-protector", "Insert stack protectors"); 769d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgFunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) { 789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org return new StackProtector(tli); 79972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org} 8081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com 8181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.combool StackProtector::runOnFunction(Function &Fn) { 829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org F = &Fn; 83972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org M = F->getParent(); 849d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 859d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org if (!RequiresStackProtector()) return false; 869d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 879d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org return InsertStackProtectors(); 889d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org} 899d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 909d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/// RequiresStackProtector - Check whether or not this function needs a stack 91972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org/// protector based upon the stack protector level. The heuristic we use is to 9281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com/// add a guard variable to functions that call alloca, and functions with 93c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com/// buffers larger than SSPBufferSize bytes. 94afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.combool StackProtector::RequiresStackProtector() const { 95c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com if (F->hasFnAttr(Attribute::StackProtectReq)) 96f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org return true; 97c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com 98972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org if (!F->hasFnAttr(Attribute::StackProtect)) 99c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com return false; 100c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com 1012047f00e4698f83499ab91911999a65c21a951c9epoger@google.com const TargetData *TD = TLI->getTargetData(); 102c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com 1039d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { 1049d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org BasicBlock *BB = I; 105e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com 10661f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com for (BasicBlock::iterator 10761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com II = BB->begin(), IE = BB->end(); II != IE; ++II) 10861f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) { 10961f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com if (AI->isArrayAllocation()) 11061f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com // This is a call to alloca with a variable size. Emit stack 11161f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com // protectors. 11261f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com return true; 113972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org 1149d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getAllocatedType())) { 1159d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org // We apparently only care about character arrays. 1169d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org if (!AT->getElementType()->isIntegerTy(8)) 117972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org continue; 118972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org 119972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org // If an array has more than SSPBufferSize bytes of allocated space, 120972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org // then we emit stack protectors. 12181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com if (SSPBufferSize <= TD->getTypeAllocSize(AT)) 122972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org return true; 123c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com } 1249d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org } 1259d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org } 1269d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 1279d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org return false; 1289d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org} 1299d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 1309d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/// InsertStackProtectors - Insert code into the prologue and epilogue of the 131972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org/// function. 13281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com/// 13381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com/// - The prologue code loads and stores the stack guard onto the stack. 13481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com/// - The epilogue checks the value stored in the prologue against the original 1359d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/// value. It calls __stack_chk_fail if they differ. 136972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgbool StackProtector::InsertStackProtectors() { 13781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com BasicBlock *FailBB = 0; // The basic block to jump to if check fails. 13881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com AllocaInst *AI = 0; // Place on stack that stores the stack guard. 1399d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org Value *StackGuardVar = 0; // The stack guard variable. 140972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org 1419d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org for (Function::iterator I = F->begin(), E = F->end(); I != E; ) { 1429d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org BasicBlock *BB = I++; 1439d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 1449d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator()); 1459d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org if (!RI) continue; 1469d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 1478d033a1b125886c62906d975b5cc28a382064526bsalomon@google.com if (!FailBB) { 14881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com // Insert code into the entry block that stores the __stack_chk_guard 149c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com // variable onto the stack: 150afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com // 151c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com // entry: 152f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org // StackGuardSlot = alloca i8* 153c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com // StackGuard = load __stack_chk_guard 1549d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org // call void @llvm.stackprotect.create(StackGuard, StackGuardSlot) 1559d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org // 1569d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org PointerType *PtrTy = PointerType::getUnqual( 1579d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org Type::getInt8Ty(RI->getContext())); 1589d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 159129b8e3237b80b9d258a8f48e8f54c0073cafbdcsenorblanco@chromium.org unsigned AddressSpace, Offset; 16094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com if (TLI->getStackCookieLocation(AddressSpace, Offset)) { 1619d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org Constant *ASPtr = Constant::getNullValue( 162972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org PointerType::get(Type::getInt8Ty(RI->getContext()), AddressSpace)); 16394b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com APInt OffsetInt(32, Offset); 1649d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org Constant *OffsetVal = Constant::getIntegerValue( 16594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com Type::getInt32Ty(RI->getContext()), OffsetInt); 16694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com StackGuardVar = ConstantExpr::getPointerCast( 1679d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org ConstantExpr::getGetElementPtr(ASPtr, &OffsetVal, 1), 1689d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org PointerType::get(PtrTy, AddressSpace)); 16994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com } else { 1709d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", PtrTy); 1719d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org } 17294b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com 1739d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org BasicBlock &Entry = F->getEntryBlock(); 1749d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org Instruction *InsPt = &Entry.front(); 17594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com 1769d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org AI = new AllocaInst(PtrTy, "StackGuardSlot", InsPt); 1779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, InsPt); 1789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 1799d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org Value *Args[] = { LI, AI }; 1809d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org CallInst:: 1819d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector), 1829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org &Args[0], array_endof(Args), "", InsPt); 1839d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 1849d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org // Create the basic block to jump to when the guard check fails. 1859d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org FailBB = CreateFailBB(); 1869d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org } 1879d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org 18869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com // For each block with a return instruction, convert this: 189972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org // 1901971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com // return: 191dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // ... 192dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // ret ... 193dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // 194dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // into this: 195f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // 196f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // return: 197f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // ... 198dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // %1 = load __stack_chk_guard 199f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // %2 = load StackGuardSlot 200f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // %3 = cmp i1 %1, %2 201f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // br i1 %3, label %SP_return, label %CallStackCheckFailBlk 202f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // 203f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // SP_return: 204f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // ret ... 205f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // 206f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // CallStackCheckFailBlk: 207f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // call void @__stack_chk_fail() 208f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org // unreachable 209f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org 2108491d24bdc3f48f67475c12c60babb9f9dba8047skia.committer@gmail.com // Split the basic block before the return instruction. 211f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return"); 212dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com 213dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // Remove default branch instruction to the new BB. 214dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com BB->getTerminator()->eraseFromParent(); 215dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com 216dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // Move the newly created basic block to the point right after the old basic 217dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // block so that it's in the "fall through" position. 218dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com NewBB->moveAfter(BB); 219dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com 220dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // Generate the stack protector instructions in the old basic block. 221dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com LoadInst *LI1 = new LoadInst(StackGuardVar, "", false, BB); 222dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com LoadInst *LI2 = new LoadInst(AI, "", true, BB); 223dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com ICmpInst *Cmp = new ICmpInst(*BB, CmpInst::ICMP_EQ, LI1, LI2, ""); 224dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com BranchInst::Create(NewBB, FailBB, Cmp, BB); 225dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com } 226dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com 227dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // Return if we didn't modify any basic blocks. I.e., there are no return 228dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com // statements in the function. 229972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org if (!FailBB) return false; 23020e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com 23120e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com return true; 23220e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com} 233972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org 234dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com/// CreateFailBB - Create a basic block to jump to when the stack protector 2351971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com/// check fails. 2361971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.comBasicBlock *StackProtector::CreateFailBB() { 2371971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com BasicBlock *FailBB = BasicBlock::Create(F->getContext(), 2381971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com "CallStackCheckFailBlk", F); 2391971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com Constant *StackChkFail = 2401971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com M->getOrInsertFunction("__stack_chk_fail", 2411971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com Type::getVoidTy(F->getContext()), NULL); 2421971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com CallInst::Create(StackChkFail, "", FailBB); 243dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com new UnreachableInst(F->getContext(), FailBB); 244dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com return FailBB; 245dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com} 2461971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com