From 6bb80512db29c02ea149f63512d05be0939aaae7 Mon Sep 17 00:00:00 2001 From: Petr Pavlu Date: Thu, 29 Nov 2018 13:22:53 +0000 Subject: [PATCH] [GlobalISel] Fix insertion of stack-protector epilogue * Tell the StackProtector pass to generate the epilogue instrumentation when GlobalISel is enabled because GISel currently does not implement the same deferred epilogue insertion as SelectionDAG. * Update StackProtector::InsertStackProtectors() to find a stack guard slot by searching for the llvm.stackprotector intrinsic when the prologue was not created by StackProtector itself but the pass still needs to generate the epilogue instrumentation. This fixes a problem when the pass would abort because the stack guard AllocInst pointer was null when generating the epilogue -- test CodeGen/AArch64/GlobalISel/arm64-irtranslator-stackprotect.ll. Differential Revision: https://reviews.llvm.org/D54518 llvm-svn: 347862 --- llvm/lib/CodeGen/StackProtector.cpp | 31 ++++++++++---- .../GlobalISel/irtranslator-stackprotect-check.ll | 50 ++++++++++++++++++++++ 2 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stackprotect-check.ll diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp index cb12c7c..dcf37ca 100644 --- a/llvm/lib/CodeGen/StackProtector.cpp +++ b/llvm/lib/CodeGen/StackProtector.cpp @@ -199,6 +199,18 @@ bool StackProtector::HasAddressTaken(const Instruction *AI) { return false; } +/// Search for the first call to the llvm.stackprotector intrinsic and return it +/// if present. +static const CallInst *findStackProtectorIntrinsic(Function &F) { + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + if (const CallInst *CI = dyn_cast(&I)) + if (CI->getCalledFunction() == + Intrinsic::getDeclaration(F.getParent(), Intrinsic::stackprotector)) + return CI; + return nullptr; +} + /// Check whether or not this function needs a stack protector based /// upon the stack protector level. /// @@ -215,13 +227,7 @@ bool StackProtector::HasAddressTaken(const Instruction *AI) { bool StackProtector::RequiresStackProtector() { bool Strong = false; bool NeedsProtector = false; - for (const BasicBlock &BB : *F) - for (const Instruction &I : BB) - if (const CallInst *CI = dyn_cast(&I)) - if (CI->getCalledFunction() == - Intrinsic::getDeclaration(F->getParent(), - Intrinsic::stackprotector)) - HasPrologue = true; + HasPrologue = findStackProtectorIntrinsic(*F); if (F->hasFnAttribute(Attribute::SafeStack)) return false; @@ -379,7 +385,8 @@ bool StackProtector::InsertStackProtectors() { // protection in SDAG. bool SupportsSelectionDAGSP = TLI->useStackGuardXorFP() || - (EnableSelectionDAGSP && !TM->Options.EnableFastISel); + (EnableSelectionDAGSP && !TM->Options.EnableFastISel && + !TM->Options.EnableGlobalISel); AllocaInst *AI = nullptr; // Place on stack that stores the stack guard. for (Function::iterator I = F->begin(), E = F->end(); I != E;) { @@ -399,6 +406,14 @@ bool StackProtector::InsertStackProtectors() { if (SupportsSelectionDAGSP) break; + // Find the stack guard slot if the prologue was not created by this pass + // itself via a previous call to CreatePrologue(). + if (!AI) { + const CallInst *SPCall = findStackProtectorIntrinsic(*F); + assert(SPCall && "Call to llvm.stackprotector is missing"); + AI = cast(SPCall->getArgOperand(1)); + } + // Set HasIRCheck to true, so that SelectionDAG will not generate its own // version. SelectionDAG called 'shouldEmitSDCheck' to check whether // instrumentation has already been generated. diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stackprotect-check.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stackprotect-check.ll new file mode 100644 index 0000000..a72691c --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stackprotect-check.ll @@ -0,0 +1,50 @@ +; RUN: llc -O0 -stop-before=irtranslator -global-isel %s -o - | FileCheck %s +; RUN: llc -O0 -stop-after=irtranslator -verify-machineinstrs -global-isel %s -o - | FileCheck --check-prefixes CHECK,CHECK-MIR %s + +; Check that when using GlobalISel, the StackProtector pass currently inserts +; both prologue and epilogue instrumentation because GlobalISel does not have +; the same epilogue insertion/optimization as SelectionDAG. + +target triple = "armv8-arm-none-eabi" + +define void @foo() ssp { +; CHECK-LABEL: entry: +; CHECK-NEXT: %StackGuardSlot = alloca i8* +; CHECK-NEXT: %0 = call i8* @llvm.stackguard() +; CHECK-NEXT: call void @llvm.stackprotector(i8* %0, i8** %StackGuardSlot) +; CHECK-NEXT: %buf = alloca [8 x i8], align 1 +; CHECK-NEXT: %1 = call i8* @llvm.stackguard() +; CHECK-NEXT: %2 = load volatile i8*, i8** %StackGuardSlot +; CHECK-NEXT: %3 = icmp eq i8* %1, %2 +; CHECK-NEXT: br i1 %3, label %SP_return, label %CallStackCheckFailBlk, !prof !0 +; +; CHECK: SP_return: +; CHECK-NEXT: ret void +; +; CHECK: CallStackCheckFailBlk: +; CHECK-NEXT: call void @__stack_chk_fail() +; CHECK-NEXT: unreachable + +; CHECK-MIR: bb.1.entry: +; CHECK-MIR: %0:_(p0) = G_FRAME_INDEX %stack.0.StackGuardSlot +; CHECK-MIR-NEXT: %1:gpr(p0) = LOAD_STACK_GUARD :: (dereferenceable invariant load 4 from @__stack_chk_guard) +; CHECK-MIR-NEXT: %2:gpr(p0) = LOAD_STACK_GUARD :: (dereferenceable invariant load 4 from @__stack_chk_guard) +; CHECK-MIR-NEXT: G_STORE %2(p0), %0(p0) :: (volatile store 4 into %stack.0.StackGuardSlot, align 8) +; CHECK-MIR-NEXT: %3:_(p0) = G_FRAME_INDEX %stack.1.buf +; CHECK-MIR-NEXT: %4:gpr(p0) = LOAD_STACK_GUARD :: (dereferenceable invariant load 4 from @__stack_chk_guard) +; CHECK-MIR-NEXT: %5:_(p0) = G_LOAD %0(p0) :: (volatile load 4 from %ir.StackGuardSlot) +; CHECK-MIR-NEXT: %6:_(s1) = G_ICMP intpred(eq), %4(p0), %5 +; CHECK-MIR-NEXT: G_BRCOND %6(s1), %bb.2 +; CHECK-MIR-NEXT: G_BR %bb.3 +; +; CHECK-MIR: bb.2.SP_return: +; CHECK-MIR-NEXT: BX_RET 14, $noreg +; +; CHECK-MIR: bb.3.CallStackCheckFailBlk: +; CHECK-MIR-NEXT: ADJCALLSTACKDOWN 0, 0, 14, $noreg, implicit-def $sp, implicit $sp +; CHECK-MIR-NEXT: BL @__stack_chk_fail, csr_aapcs, implicit-def $lr, implicit $sp +; CHECK-MIR-NEXT: ADJCALLSTACKUP 0, 0, 14, $noreg, implicit-def $sp, implicit $sp +entry: + %buf = alloca [8 x i8], align 1 + ret void +} -- 2.7.4