Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -995,13 +995,9 @@ 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 { @@ -1952,6 +1948,8 @@ /// Stores the CallingConv that should be used for each libcall. CallingConv::ID LibcallCallingConvs[RTLIB::UNKNOWN_LIBCALL]; + const char *kAndroidUnsafeStackPtrAddrFn = "__safestack_pointer_address"; + protected: /// Return true if the extension represented by \p I is free. /// \pre \p I is a sign, zero, or fp extension and Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -1662,6 +1662,18 @@ } } +/// Android provides a libc function to retrieve the address of the current +/// thread's unsafe stack pointer. +Value *TargetLoweringBase::getSafeStackPointerLocation(IRBuilder<> &IRB) const { + if (TM.getTargetTriple().getEnvironment() != llvm::Triple::Android) + return nullptr; + Module *M = IRB.GetInsertBlock()->getParent()->getParent(); + Value *Fn = M->getOrInsertFunction( + kAndroidUnsafeStackPtrAddrFn, + Type::getInt8PtrTy(M->getContext())->getPointerTo(0), nullptr); + return IRB.CreateCall(Fn); +} + //===----------------------------------------------------------------------===// // Loop Strength Reduction hooks //===----------------------------------------------------------------------===// Index: lib/Target/AArch64/AArch64ISelLowering.h =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.h +++ lib/Target/AArch64/AArch64ISelLowering.h @@ -362,6 +362,10 @@ 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; Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -9750,3 +9750,19 @@ EVT) const { return false; } + +/// 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 +Value *AArch64TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB) const { + if (!Subtarget->isTargetAndroid()) + return nullptr; + + const unsigned kTlsOffset = 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), kTlsOffset), + Type::getInt8PtrTy(IRB.getContext())->getPointerTo(0)); +} Index: lib/Target/AArch64/AArch64Subtarget.h =================================================================== --- lib/Target/AArch64/AArch64Subtarget.h +++ lib/Target/AArch64/AArch64Subtarget.h @@ -123,6 +123,9 @@ bool isTargetIOS() const { return TargetTriple.isiOS(); } bool isTargetLinux() const { return TargetTriple.isOSLinux(); } bool isTargetWindows() const { return TargetTriple.isOSWindows(); } + bool isTargetAndroid() const { + return TargetTriple.getEnvironment() == Triple::Android; + } bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); } bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -897,8 +897,7 @@ /// 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; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -2083,11 +2083,11 @@ /// 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 nullptr; + unsigned AddressSpace, Offset; if (Subtarget->is64Bit()) { // %fs:0x48, unless we're using a Kernel code model, in which case it's %gs: Offset = 0x48; @@ -2100,7 +2100,10 @@ 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, Index: lib/Transforms/Instrumentation/SafeStack.cpp =================================================================== --- lib/Transforms/Instrumentation/SafeStack.cpp +++ lib/Transforms/Instrumentation/SafeStack.cpp @@ -47,7 +47,6 @@ #define DEBUG_TYPE "safestack" static const char *const kUnsafeStackPtrVar = "__safestack_unsafe_stack_ptr"; -static const char *const kUnsafeStackPtrAddrFn = "__safestack_pointer_address"; namespace llvm { @@ -251,48 +250,39 @@ 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 the target provides a standard location for the unsafe stack + // pointer. + if (TLI) { + Value *Ptr = TLI->getSafeStackPointerLocation(IRB); + if (Ptr) + return Ptr; } - // Android provides a libc function that returns the stack pointer address. - if (TargetTriple.getEnvironment() == llvm::Triple::Android) { - Value *Fn = M.getOrInsertFunction(kUnsafeStackPtrAddrFn, - StackPtrTy->getPointerTo(0), nullptr); - return IRB.CreateCall(Fn); + // 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=*/0, /*Name=*/kUnsafeStackPtrVar, + /*InsertBefore=*/nullptr, + /*ThreadLocalMode=*/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=*/0, /*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"); - } + // 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"); - } + if (!UnsafeStackPtr->isThreadLocal()) { + report_fatal_error(Twine(kUnsafeStackPtrVar) + " must be thread-local"); } - return UnsafeStackPtr; } + return UnsafeStackPtr; } void SafeStack::findInsts(Function &F, Index: test/Transforms/SafeStack/AArch64/abi.ll =================================================================== --- test/Transforms/SafeStack/AArch64/abi.ll +++ 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]]