Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -1061,8 +1061,13 @@ virtual Value *getSDagStackGuard(const Module &M) const; /// 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 the address of that location. + /// If Offset is non-zero, returns the address of that byte offset within the + /// thread control block (if supported). This ignores the standard location + /// even if one is defined. + /// Otherwise, returns nullptr. + virtual Value *getSafeStackPointerLocation(IRBuilder<> &IRB, + unsigned Offset) const; /// Returns true if a cast between SrcAS and DestAS is a noop. virtual bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const { Index: lib/CodeGen/SafeStack.cpp =================================================================== --- lib/CodeGen/SafeStack.cpp +++ lib/CodeGen/SafeStack.cpp @@ -50,17 +50,28 @@ #define DEBUG_TYPE "safestack" -enum UnsafeStackPtrStorageVal { ThreadLocalUSP, SingleThreadUSP }; +enum UnsafeStackPtrStorageVal { + ThreadLocalUSP, + ThreadControlBlockUSP, + SingleThreadUSP +}; static cl::opt USPStorage("safe-stack-usp-storage", cl::Hidden, cl::init(ThreadLocalUSP), cl::desc("Type of storage for the unsafe stack pointer"), cl::values(clEnumValN(ThreadLocalUSP, "thread-local", "Thread-local storage"), + clEnumValN(ThreadControlBlockUSP, "tcb", + "Thread control block " + "(specify -safe-stack-usp-tcb-offset)"), clEnumValN(SingleThreadUSP, "single-thread", "Non-thread-local storage"), clEnumValEnd)); +static cl::opt USPTCBOffset("safe-stack-usp-tcb-offset", + cl::Hidden, + cl::desc("Thread control block offset for unsafe stack pointer")); + static cl::opt USPInit("safe-stack-usp-init", cl::Hidden, cl::init(false), cl::desc("Use a single-threaded variable as the unsafe stack pointer " @@ -439,13 +450,24 @@ IRB.CreateLoad(UnsafeStackPtrInit, false, "unsafe_stack_ptr_init"); } + unsigned TCBOffset = 0; + if (USPStorage == ThreadControlBlockUSP) { + TCBOffset = USPTCBOffset; + + assert(TCBOffset != 0 && + "Thread control block offset for unsafe stack pointer must be " + "specified with -safe-stack-usp-tcb-offset."); + } // Check if there is a target-specific location for the unsafe stack pointer. if (TL) { - UnsafeStackPtr = TL->getSafeStackPointerLocation(IRB); + UnsafeStackPtr = TL->getSafeStackPointerLocation(IRB, TCBOffset); if (UnsafeStackPtr) return loadUnsafeStackPtr(IRB, true); } + assert(USPStorage != ThreadControlBlockUSP && + "Location should have been computed by getSafeStackPointerLocation."); + // Otherwise, assume the target links with compiler-rt, which provides a // thread-local variable with a magic name. const char *UnsafeStackPtrName = "__safestack_unsafe_stack_ptr"; Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -1753,7 +1753,10 @@ } } -Value *TargetLoweringBase::getSafeStackPointerLocation(IRBuilder<> &IRB) const { +Value *TargetLoweringBase::getSafeStackPointerLocation(IRBuilder<> &IRB, + unsigned Offset) const { + assert(Offset == 0 && "Thread control block offset not supported."); + if (!TM.getTargetTriple().isAndroid()) return nullptr; Index: lib/Target/AArch64/AArch64ISelLowering.h =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.h +++ lib/Target/AArch64/AArch64ISelLowering.h @@ -363,8 +363,13 @@ Value *getIRStackGuard(IRBuilder<> &IRB) 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; + /// returns the address of that location. + /// If Offset is non-zero, returns the address of that byte offset within the + /// thread control block. This ignores the standard location even if one is + /// defined. + /// Otherwise, returns nullptr. + Value *getSafeStackPointerLocation(IRBuilder<> &IRB, + unsigned Offset) const override; /// If a physical register, this returns the register that receives the /// exception address on entry to an EH pad. Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10274,19 +10274,21 @@ Type::getInt8PtrTy(IRB.getContext())->getPointerTo(0)); } -Value *AArch64TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB) const { - if (!Subtarget->isTargetAndroid()) - return TargetLowering::getSafeStackPointerLocation(IRB); +Value *AArch64TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB, + unsigned Offset) const { + if (!Subtarget->isTargetAndroid() && Offset == 0) + return TargetLowering::getSafeStackPointerLocation(IRB, Offset); // 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; + if (Offset == 0) + Offset = 0x48; Module *M = IRB.GetInsertBlock()->getParent()->getParent(); Function *ThreadPointerFunc = Intrinsic::getDeclaration(M, Intrinsic::thread_pointer); return IRB.CreatePointerCast( - IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), TlsOffset), + IRB.CreateConstGEP1_32(IRB.CreateCall(ThreadPointerFunc), Offset), Type::getInt8PtrTy(IRB.getContext())->getPointerTo(0)); } Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -967,10 +967,14 @@ void insertSSPDeclarations(Module &M) const override; - /// 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. - Value *getSafeStackPointerLocation(IRBuilder<> &IRB) const override; + /// If the target has a standard location for the unsafe stack pointer, + /// returns the address of that location. + /// If Offset is non-zero, returns the address of that byte offset within the + /// thread control block. This ignores the standard location even if one is + /// defined. + /// Otherwise, returns nullptr. + Value *getSafeStackPointerLocation(IRBuilder<> &IRB, + unsigned Offset) 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 @@ -1940,18 +1940,20 @@ TargetLowering::insertSSPDeclarations(M); } -Value *X86TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB) const { - if (!Subtarget.isTargetAndroid()) - return TargetLowering::getSafeStackPointerLocation(IRB); +Value *X86TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB, + unsigned Offset) const { + if (!Subtarget.isTargetAndroid() && Offset == 0) + return TargetLowering::getSafeStackPointerLocation(IRB, Offset); // 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; + unsigned AddressSpace; // %fs:0x48, unless we're using a Kernel code model, in which case it's %gs: // %gs:0x24 on i386 - Offset = (Subtarget.is64Bit()) ? 0x48 : 0x24; + if (Offset == 0) + Offset = (Subtarget.is64Bit()) ? 0x48 : 0x24; AddressSpace = getAddressSpace(); return ConstantExpr::getIntToPtr( ConstantInt::get(Type::getInt32Ty(IRB.getContext()), Offset), Index: test/Transforms/SafeStack/addr-taken.ll =================================================================== --- test/Transforms/SafeStack/addr-taken.ll +++ test/Transforms/SafeStack/addr-taken.ll @@ -1,5 +1,6 @@ ; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s ; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu -safe-stack-usp-storage=tcb -safe-stack-usp-tcb-offset=40 < %s -o - | FileCheck --check-prefix TCB %s @.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 @@ -9,6 +10,9 @@ define void @foo() nounwind uwtable safestack { entry: ; CHECK: __safestack_unsafe_stack_ptr + ; TCB: %unsafe_stack_ptr = load i8*, i8* addrspace(256)* inttoptr (i32 40 to i8* addrspace(256)*) + ; TCB-NEXT: %unsafe_stack_static_top = getelementptr i8, i8* %unsafe_stack_ptr, i32 -16 + ; TCB-NEXT: store i8* %unsafe_stack_static_top, i8* addrspace(256)* inttoptr (i32 40 to i8* addrspace(256)*) %retval = alloca i32, align 4 %a = alloca i32, align 4 %j = alloca i32*, align 8 @@ -17,6 +21,7 @@ %add = add nsw i32 %0, 1 store i32 %add, i32* %a, align 4 store i32* %a, i32** %j, align 8 + ; TCB: store i8* %unsafe_stack_ptr, i8* addrspace(256)* inttoptr (i32 40 to i8* addrspace(256)*) ret void }