From: Evgeniy Stepanov Date: Mon, 26 Oct 2015 18:28:25 +0000 (+0000) Subject: [safestack] Fast access to the unsafe stack pointer on AArch64/Android. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=324bf0ddcc8acfaba6c07415335a978ba3f0a57f;p=oota-llvm.git [safestack] Fast access to the unsafe stack pointer on AArch64/Android. Android libc provides a fixed TLS slot for the unsafe stack pointer, and this change implements direct access to that slot on AArch64 via __builtin_thread_pointer() + offset. This change also moves more code into TargetLowering and its target-specific subclasses to get rid of target-specific codegen in SafeStackPass. This change does not touch the ARM backend because ARM lowers builting_thread_pointer as aeabi_read_tp, which is not available on Android. The previous iteration of this change was reverted in r250461. This version leaves the generic, compiler-rt based implementation in SafeStack.cpp instead of moving it to TargetLoweringBase in order to allow testing without a TargetMachine. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251324 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 4d1208ff51a..e17682f704e 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -996,13 +996,9 @@ public: return false; } - /// Return true if the target stores SafeStack pointer at a fixed offset in - /// some non-standard address space, and populates the address space and - /// offset as appropriate. - virtual bool getSafeStackPointerLocation(unsigned & /*AddressSpace*/, - unsigned & /*Offset*/) const { - return false; - } + /// If the target has a standard location for the unsafe stack pointer, + /// returns the address of that location. Otherwise, returns nullptr. + virtual Value *getSafeStackPointerLocation(IRBuilder<> &IRB) const; /// Returns true if a cast between SrcAS and DestAS is a noop. virtual bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const { diff --git a/lib/CodeGen/TargetLoweringBase.cpp b/lib/CodeGen/TargetLoweringBase.cpp index 7250fdc9385..ece2e395c3d 100644 --- a/lib/CodeGen/TargetLoweringBase.cpp +++ b/lib/CodeGen/TargetLoweringBase.cpp @@ -1662,6 +1662,19 @@ TargetLoweringBase::getTypeLegalizationCost(const DataLayout &DL, } } +Value *TargetLoweringBase::getSafeStackPointerLocation(IRBuilder<> &IRB) const { + if (!TM.getTargetTriple().isAndroid()) + return nullptr; + + // Android provides a libc function to retrieve the address of the current + // thread's unsafe stack pointer. + Module *M = IRB.GetInsertBlock()->getParent()->getParent(); + Type *StackPtrTy = Type::getInt8PtrTy(M->getContext()); + Value *Fn = M->getOrInsertFunction("__safestack_pointer_address", + StackPtrTy->getPointerTo(0), nullptr); + return IRB.CreateCall(Fn); +} + //===----------------------------------------------------------------------===// // Loop Strength Reduction hooks //===----------------------------------------------------------------------===// diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index 241e139009f..fd33f879d4c 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -9951,3 +9951,19 @@ bool AArch64TargetLowering::shouldNormalizeToSelectSequence(LLVMContext &, EVT) const { return false; } + +Value *AArch64TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB) const { + if (!Subtarget->isTargetAndroid()) + return TargetLowering::getSafeStackPointerLocation(IRB); + + // Android provides a fixed TLS slot for the SafeStack pointer. See the + // definition of TLS_SLOT_SAFESTACK in + // https://android.googlesource.com/platform/bionic/+/master/libc/private/bionic_tls.h + const unsigned TlsOffset = 0x48; + Module *M = IRB.GetInsertBlock()->getParent()->getParent(); + Function *ThreadPointerFunc = + Intrinsic::getDeclaration(M, Intrinsic::aarch64_thread_pointer); + return IRB.CreatePointerCast( + IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), TlsOffset), + Type::getInt8PtrTy(IRB.getContext())->getPointerTo(0)); +} diff --git a/lib/Target/AArch64/AArch64ISelLowering.h b/lib/Target/AArch64/AArch64ISelLowering.h index b815f55da6b..64a2934d1d5 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.h +++ b/lib/Target/AArch64/AArch64ISelLowering.h @@ -362,6 +362,10 @@ public: TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(EVT VT) const override; + /// If the target has a standard location for the unsafe stack pointer, + /// returns the address of that location. Otherwise, returns nullptr. + Value *getSafeStackPointerLocation(IRBuilder<> &IRB) const override; + private: bool isExtFreeImpl(const Instruction *Ext) const override; diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 98bb411913e..63c2b9a21dc 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -2128,14 +2128,14 @@ bool X86TargetLowering::getStackCookieLocation(unsigned &AddressSpace, return true; } -/// Android provides a fixed TLS slot for the SafeStack pointer. -/// See the definition of TLS_SLOT_SAFESTACK in -/// https://android.googlesource.com/platform/bionic/+/master/libc/private/bionic_tls.h -bool X86TargetLowering::getSafeStackPointerLocation(unsigned &AddressSpace, - unsigned &Offset) const { +Value *X86TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB) const { if (!Subtarget->isTargetAndroid()) - return false; + return TargetLowering::getSafeStackPointerLocation(IRB); + // Android provides a fixed TLS slot for the SafeStack pointer. See the + // definition of TLS_SLOT_SAFESTACK in + // https://android.googlesource.com/platform/bionic/+/master/libc/private/bionic_tls.h + unsigned AddressSpace, Offset; if (Subtarget->is64Bit()) { // %fs:0x48, unless we're using a Kernel code model, in which case it's %gs: Offset = 0x48; @@ -2148,7 +2148,10 @@ bool X86TargetLowering::getSafeStackPointerLocation(unsigned &AddressSpace, Offset = 0x24; AddressSpace = 256; } - return true; + + return ConstantExpr::getIntToPtr( + ConstantInt::get(Type::getInt32Ty(IRB.getContext()), Offset), + Type::getInt8PtrTy(IRB.getContext())->getPointerTo(AddressSpace)); } bool X86TargetLowering::isNoopAddrSpaceCast(unsigned SrcAS, diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 7b44f431428..a7ea21e52a8 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -903,8 +903,7 @@ namespace llvm { /// Return true if the target stores SafeStack pointer at a fixed offset in /// some non-standard address space, and populates the address space and /// offset as appropriate. - bool getSafeStackPointerLocation(unsigned &AddressSpace, - unsigned &Offset) const override; + Value *getSafeStackPointerLocation(IRBuilder<> &IRB) const override; SDValue BuildFILD(SDValue Op, EVT SrcVT, SDValue Chain, SDValue StackSlot, SelectionDAG &DAG) const; diff --git a/lib/Transforms/Instrumentation/SafeStack.cpp b/lib/Transforms/Instrumentation/SafeStack.cpp index 96ef639138a..f63f3a5f45f 100644 --- a/lib/Transforms/Instrumentation/SafeStack.cpp +++ b/lib/Transforms/Instrumentation/SafeStack.cpp @@ -46,9 +46,6 @@ using namespace llvm; #define DEBUG_TYPE "safestack" -static const char *const kUnsafeStackPtrVar = "__safestack_unsafe_stack_ptr"; -static const char *const kUnsafeStackPtrAddrFn = "__safestack_pointer_address"; - namespace llvm { STATISTIC(NumFunctions, "Total number of functions"); @@ -182,8 +179,7 @@ class SafeStack : public FunctionPass { /// might expect to appear on the stack on most common targets. enum { StackAlignment = 16 }; - /// \brief Build a constant representing a pointer to the unsafe stack - /// pointer. + /// \brief Build a value representing a pointer to the unsafe stack pointer. Value *getOrCreateUnsafeStackPtr(IRBuilder<> &IRB, Function &F); /// \brief Find all static allocas, dynamic allocas, return instructions and @@ -248,51 +244,33 @@ public: }; // class SafeStack Value *SafeStack::getOrCreateUnsafeStackPtr(IRBuilder<> &IRB, Function &F) { - Module &M = *F.getParent(); - Triple TargetTriple(M.getTargetTriple()); - - unsigned Offset; - unsigned AddressSpace; - // Check if the target keeps the unsafe stack pointer at a fixed offset. - if (TLI && TLI->getSafeStackPointerLocation(AddressSpace, Offset)) { - Constant *OffsetVal = - ConstantInt::get(Type::getInt32Ty(F.getContext()), Offset); - return ConstantExpr::getIntToPtr(OffsetVal, - StackPtrTy->getPointerTo(AddressSpace)); - } + // Check if there is a target-specific location for the unsafe stack pointer. + if (TLI) + if (Value *V = TLI->getSafeStackPointerLocation(IRB)) + return V; - // Android provides a libc function that returns the stack pointer address. - if (TargetTriple.isAndroid()) { - Value *Fn = M.getOrInsertFunction(kUnsafeStackPtrAddrFn, - StackPtrTy->getPointerTo(0), nullptr); - return IRB.CreateCall(Fn); + // Otherwise, assume the target links with compiler-rt, which provides a + // thread-local variable with a magic name. + Module &M = *F.getParent(); + const char *UnsafeStackPtrVar = "__safestack_unsafe_stack_ptr"; + auto UnsafeStackPtr = + dyn_cast_or_null(M.getNamedValue(UnsafeStackPtrVar)); + + if (!UnsafeStackPtr) { + // The global variable is not defined yet, define it ourselves. + // We use the initial-exec TLS model because we do not support the + // variable living anywhere other than in the main executable. + UnsafeStackPtr = new GlobalVariable( + M, StackPtrTy, false, GlobalValue::ExternalLinkage, 0, + UnsafeStackPtrVar, nullptr, GlobalValue::InitialExecTLSModel); } else { - // Otherwise, declare a thread-local variable with a magic name. - auto UnsafeStackPtr = - dyn_cast_or_null(M.getNamedValue(kUnsafeStackPtrVar)); - - if (!UnsafeStackPtr) { - // The global variable is not defined yet, define it ourselves. - // We use the initial-exec TLS model because we do not support the - // variable living anywhere other than in the main executable. - UnsafeStackPtr = new GlobalVariable( - /*Module=*/M, /*Type=*/StackPtrTy, - /*isConstant=*/false, /*Linkage=*/GlobalValue::ExternalLinkage, - /*Initializer=*/nullptr, /*Name=*/kUnsafeStackPtrVar, - /*InsertBefore=*/nullptr, - /*ThreadLocalMode=*/GlobalValue::InitialExecTLSModel); - } else { - // The variable exists, check its type and attributes. - if (UnsafeStackPtr->getValueType() != StackPtrTy) { - report_fatal_error(Twine(kUnsafeStackPtrVar) + " must have void* type"); - } - - if (!UnsafeStackPtr->isThreadLocal()) { - report_fatal_error(Twine(kUnsafeStackPtrVar) + " must be thread-local"); - } - } - return UnsafeStackPtr; + // The variable exists, check its type and attributes. + if (UnsafeStackPtr->getValueType() != StackPtrTy) + report_fatal_error(Twine(UnsafeStackPtrVar) + " must have void* type"); + if (!UnsafeStackPtr->isThreadLocal()) + report_fatal_error(Twine(UnsafeStackPtrVar) + " must be thread-local"); } + return UnsafeStackPtr; } void SafeStack::findInsts(Function &F, diff --git a/test/Transforms/SafeStack/AArch64/abi.ll b/test/Transforms/SafeStack/AArch64/abi.ll index 942658a89d2..cdec923eb74 100644 --- a/test/Transforms/SafeStack/AArch64/abi.ll +++ b/test/Transforms/SafeStack/AArch64/abi.ll @@ -3,7 +3,9 @@ define void @foo() nounwind uwtable safestack { entry: -; CHECK: %[[SPA:.*]] = call i8** @__safestack_pointer_address() +; CHECK: %[[TP:.*]] = call i8* @llvm.aarch64.thread.pointer() +; CHECK: %[[SPA0:.*]] = getelementptr i8, i8* %[[TP]], i32 72 +; CHECK: %[[SPA:.*]] = bitcast i8* %[[SPA0]] to i8** ; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]] ; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 ; CHECK: store i8* %[[USST]], i8** %[[SPA]]