Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1523,6 +1523,17 @@ function that doesn't have a ``safestack`` attribute or which has an ``ssp``, ``sspstrong`` or ``sspreq`` attribute, then the resulting function will have a ``safestack`` attribute. +``safestack_call_for_usp`` + This attribute causes the `SafeStack + `_ pass to call the + ``__safestack_pointer_address`` function to obtain the location of the + unsafe stack pointer. The ``__safestack_pointer_address`` function may be + provided by a runtime library. This attribute may be useful for functions + that may be used both during initialization of a dynamic linker or language + runtime and later, after the default (e.g. thread-local) unsafe stack + pointer is configured. For example, prior to initialization of thread-local + storage, the ``__safestack_pointer_address`` function may return a pointer + to a non-thread-local variable. ``sanitize_address`` This attribute indicates that AddressSanitizer checks (dynamic address safety analysis) are enabled for this function. Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -516,7 +516,8 @@ ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50, ATTR_KIND_ALLOC_SIZE = 51, - ATTR_KIND_WRITEONLY = 52 + ATTR_KIND_WRITEONLY = 52, + ATTR_KIND_SAFESTACK_CALL_FOR_USP = 53 }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -130,6 +130,9 @@ /// Safe Stack protection. def SafeStack : EnumAttr<"safestack">; +/// Call __safestack_pointer_address to locate the unsafe stack pointer. +def SafeStackCallForUSP : EnumAttr<"safestack_call_for_usp">; + /// Sign extended before/after call. def SExt : EnumAttr<"signext">; Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -649,6 +649,7 @@ KEYWORD(sspreq); KEYWORD(sspstrong); KEYWORD(safestack); + KEYWORD(safestack_call_for_usp); KEYWORD(sanitize_address); KEYWORD(sanitize_thread); KEYWORD(sanitize_memory); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1112,6 +1112,8 @@ case lltok::kw_sspstrong: B.addAttribute(Attribute::StackProtectStrong); break; case lltok::kw_safestack: B.addAttribute(Attribute::SafeStack); break; + case lltok::kw_safestack_call_for_usp: + B.addAttribute(Attribute::SafeStackCallForUSP); break; case lltok::kw_sanitize_address: B.addAttribute(Attribute::SanitizeAddress); break; case lltok::kw_sanitize_thread: @@ -1442,6 +1444,7 @@ case lltok::kw_ssp: case lltok::kw_sspreq: case lltok::kw_sspstrong: + case lltok::kw_safestack_call_for_usp: case lltok::kw_safestack: case lltok::kw_uwtable: HaveError |= Error(Lex.getLoc(), "invalid use of function-only attribute"); @@ -1527,6 +1530,7 @@ case lltok::kw_optnone: case lltok::kw_optsize: case lltok::kw_returns_twice: + case lltok::kw_safestack_call_for_usp: case lltok::kw_sanitize_address: case lltok::kw_sanitize_memory: case lltok::kw_sanitize_thread: Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -200,6 +200,7 @@ kw_sspreq, kw_sspstrong, kw_safestack, + kw_safestack_call_for_usp, kw_sret, kw_sanitize_thread, kw_sanitize_memory, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1568,6 +1568,8 @@ return Attribute::StackProtectStrong; case bitc::ATTR_KIND_SAFESTACK: return Attribute::SafeStack; + case bitc::ATTR_KIND_SAFESTACK_CALL_FOR_USP: + return Attribute::SafeStackCallForUSP; case bitc::ATTR_KIND_STRUCT_RET: return Attribute::StructRet; case bitc::ATTR_KIND_SANITIZE_ADDRESS: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -700,6 +700,8 @@ return bitc::ATTR_KIND_STACK_PROTECT_STRONG; case Attribute::SafeStack: return bitc::ATTR_KIND_SAFESTACK; + case Attribute::SafeStackCallForUSP: + return bitc::ATTR_KIND_SAFESTACK_CALL_FOR_USP; case Attribute::StructRet: return bitc::ATTR_KIND_STRUCT_RET; case Attribute::SanitizeAddress: Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -1800,12 +1800,15 @@ } Value *TargetLoweringBase::getSafeStackPointerLocation(IRBuilder<> &IRB) const { - if (!TM.getTargetTriple().isAndroid()) + Function *F = IRB.GetInsertBlock()->getParent(); + if (!(TM.getTargetTriple().isAndroid() || + F->hasFnAttribute(Attribute::SafeStackCallForUSP))) return getDefaultSafeStackPointerLocation(IRB, true); // Android provides a libc function to retrieve the address of the current - // thread's unsafe stack pointer. - Module *M = IRB.GetInsertBlock()->getParent()->getParent(); + // thread's unsafe stack pointer. The safestack_call_for_usp attribute can be + // used on non-Android targets to force usage of a similarly-named function. + Module *M = F->getParent(); Type *StackPtrTy = Type::getInt8PtrTy(M->getContext()); Value *Fn = M->getOrInsertFunction("__safestack_pointer_address", StackPtrTy->getPointerTo(0), nullptr); Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -308,6 +308,8 @@ return "sspstrong"; if (hasAttribute(Attribute::SafeStack)) return "safestack"; + if (hasAttribute(Attribute::SafeStackCallForUSP)) + return "safestack_call_for_usp"; if (hasAttribute(Attribute::StructRet)) return "sret"; if (hasAttribute(Attribute::SanitizeThread)) @@ -527,6 +529,7 @@ case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; + case Attribute::SafeStackCallForUSP: return 1ULL << 54; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1304,6 +1304,7 @@ I->getKindAsEnum() == Attribute::StackProtectReq || I->getKindAsEnum() == Attribute::StackProtectStrong || I->getKindAsEnum() == Attribute::SafeStack || + I->getKindAsEnum() == Attribute::SafeStackCallForUSP || I->getKindAsEnum() == Attribute::NoRedZone || I->getKindAsEnum() == Attribute::NoImplicitFloat || I->getKindAsEnum() == Attribute::Naked || Index: lib/Transforms/IPO/ForceFunctionAttrs.cpp =================================================================== --- lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -51,6 +51,7 @@ .Case("argmemonly", Attribute::ArgMemOnly) .Case("returns_twice", Attribute::ReturnsTwice) .Case("safestack", Attribute::SafeStack) + .Case("safestack_call_for_usp", Attribute::SafeStackCallForUSP) .Case("sanitize_address", Attribute::SanitizeAddress) .Case("sanitize_memory", Attribute::SanitizeMemory) .Case("sanitize_thread", Attribute::SanitizeThread) Index: test/Transforms/SafeStack/call-for-usp.ll =================================================================== --- /dev/null +++ test/Transforms/SafeStack/call-for-usp.ll @@ -0,0 +1,20 @@ +; 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 + +; Load from an array at a fixed offset with overflow. +define i8 @StaticArrayFixedUnsafe() nounwind uwtable safestack safestack_call_for_usp { +entry: + ; CHECK-LABEL: define i8 @StaticArrayFixedUnsafe( + ; CHECK: %0 = call i8** @__safestack_pointer_address() + ; CHECK-NEXT: %unsafe_stack_ptr = load i8*, i8** %0 + ; CHECK-NEXT: %unsafe_stack_static_top = getelementptr i8, i8* %unsafe_stack_ptr, i32 -16 + ; CHECK-NEXT: store i8* %unsafe_stack_static_top, i8** %0 + ; CHECK: store i8* %unsafe_stack_ptr, i8** %0 + + %buf = alloca i8, i32 4, align 1 + %gep = getelementptr inbounds i8, i8* %buf, i32 5 + %x = load i8, i8* %gep, align 1 + ret i8 %x +} + +; CHECK: declare i8** @__safestack_pointer_address()