Index: lib/Transforms/Instrumentation/SafeStack.cpp =================================================================== --- lib/Transforms/Instrumentation/SafeStack.cpp +++ lib/Transforms/Instrumentation/SafeStack.cpp @@ -47,6 +47,17 @@ #define DEBUG_TYPE "safestack" +enum UnsafeStackPtrStorageVal { ThreadLocalUSP, 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(SingleThreadUSP, "single-thread", + "Non-thread-local storage"), + clEnumValEnd)); + namespace llvm { STATISTIC(NumFunctions, "Total number of functions"); @@ -344,19 +355,25 @@ auto UnsafeStackPtr = dyn_cast_or_null(M.getNamedValue(UnsafeStackPtrVar)); + bool UseTLS = USPStorage == ThreadLocalUSP; + if (!UnsafeStackPtr) { + auto TLSModel = UseTLS ? + GlobalValue::InitialExecTLSModel : + GlobalValue::NotThreadLocal; // 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, nullptr, - UnsafeStackPtrVar, nullptr, GlobalValue::InitialExecTLSModel); + UnsafeStackPtrVar, nullptr, TLSModel); } else { // 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"); + if (UseTLS != UnsafeStackPtr->isThreadLocal()) + report_fatal_error(Twine(UnsafeStackPtrVar) + " must " + + (UseTLS ? "" : "not ") + "be thread-local"); } return UnsafeStackPtr; } Index: test/Transforms/SafeStack/array.ll =================================================================== --- test/Transforms/SafeStack/array.ll +++ test/Transforms/SafeStack/array.ll @@ -1,9 +1,14 @@ ; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -safe-stack-usp-storage=single-thread -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck -check-prefix=SINGLE-THREAD %s ; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -safe-stack-usp-storage=single-thread -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck -check-prefix=SINGLE-THREAD %s ; array [4 x i8] ; Requires protector. +; CHECK: @__safestack_unsafe_stack_ptr = external thread_local(initialexec) global i8* +; SINGLE-THREAD: @__safestack_unsafe_stack_ptr = external global i8* + define void @foo(i8* %a) nounwind uwtable safestack { entry: ; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr