Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -169,6 +169,13 @@ virtual bool useSoftFloat() const { return false; } + /// A target may require that no pointer passed from one function to another + /// points to the main stack. Such a target must override this function to + /// return true. SafeStack must always be used for such a target, to move + /// any stack allocation to the unsafe stack that is the target of a pointer + /// passed to a subroutine. + virtual bool useOnlyLocalStackPointers() const { return false; } + /// Return the pointer type for the given address space, defaults to /// the pointer type from the data layout. /// FIXME: The default needs to be removed once all the code is updated. Index: lib/CodeGen/SafeStack.cpp =================================================================== --- lib/CodeGen/SafeStack.cpp +++ lib/CodeGen/SafeStack.cpp @@ -314,6 +314,11 @@ continue; } + // FIXME: A more precise solution may consider whether particular types + // of intrinsics necessitate moving allocations to the unsafe stack. + if (TL->useOnlyLocalStackPointers()) + return false; + if (const MemIntrinsic *MI = dyn_cast(I)) { if (!IsMemIntrinsicSafe(MI, UI, AllocaPtr, AllocaSize)) { DEBUG(dbgs() << "[SafeStack] Unsafe alloca: " << *AllocaPtr Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -655,6 +655,7 @@ unsigned getJumpTableEncoding() const override; bool useSoftFloat() const override; + bool useOnlyLocalStackPointers() const override; MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override { return MVT::i8; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -1985,6 +1985,10 @@ return Subtarget.useSoftFloat(); } +bool X86TargetLowering::useOnlyLocalStackPointers() const { + return Subtarget.useSeparateStackSeg(); +} + const MCExpr * X86TargetLowering::LowerCustomJumpTableEntry(const MachineJumpTableInfo *MJTI, const MachineBasicBlock *MBB, Index: test/Transforms/SafeStack/call.ll =================================================================== --- test/Transforms/SafeStack/call.ll +++ test/Transforms/SafeStack/call.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 -mattr=+separate-stack-seg < %s -o - | FileCheck --check-prefix SEP-STK %s @.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 @@ -11,6 +12,9 @@ ; CHECK-LABEL: define void @foo( ; CHECK-NOT: __safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @foo( + ; SEP-STK-NOT: __safestack_unsafe_stack_ptr + ; SEP-STK: ret void %a.addr = alloca i8*, align 8 store i8* %a, i8** %a.addr, align 8 %0 = load i8*, i8** %a.addr, align 8 @@ -28,6 +32,9 @@ ; CHECK-LABEL: define void @call_memset ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_memset + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 %len, i32 1, i1 false) @@ -39,6 +46,9 @@ ; CHECK-LABEL: define void @call_constant_memset ; CHECK-NOT: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_constant_memset + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 2 call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 7, i32 1, i1 false) @@ -50,6 +60,9 @@ ; CHECK-LABEL: define void @call_constant_overflow_memset ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_constant_overflow_memset + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 7 call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 5, i32 1, i1 false) @@ -61,6 +74,9 @@ ; CHECK-LABEL: define void @call_constant_underflow_memset ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_constant_underflow_memset + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr [10 x i8], [10 x i8]* %q, i32 0, i32 -1 call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 3, i32 1, i1 false) @@ -73,6 +89,9 @@ ; CHECK-LABEL: define void @call_readnone ; CHECK-NOT: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_readnone + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @readnone(i8* %arraydecay) @@ -85,6 +104,9 @@ ; CHECK-LABEL: define void @call_readnone0_0 ; CHECK-NOT: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_readnone0_0 + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @readnone0(i8* %arraydecay, i8* zeroinitializer) @@ -97,6 +119,9 @@ ; CHECK-LABEL: define void @call_readnone0_1 ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_readnone0_1 + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @readnone0(i8 *zeroinitializer, i8* %arraydecay) @@ -109,6 +134,9 @@ ; CHECK-LABEL: define void @call_readonly ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_readonly + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @readonly(i8* %arraydecay) @@ -121,6 +149,9 @@ ; CHECK-LABEL: define void @call_arg_readonly ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_arg_readonly + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @arg_readonly(i8* %arraydecay) @@ -133,6 +164,9 @@ ; CHECK-LABEL: define void @call_readwrite ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_readwrite + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @readwrite(i8* %arraydecay) @@ -145,6 +179,9 @@ ; CHECK-LABEL: define void @call_capture ; CHECK: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_capture + ; SEP-STK: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void %q = alloca [10 x i8], align 1 %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0 call void @capture(i8* %arraydecay) @@ -156,6 +193,9 @@ ; CHECK-LABEL: define void @call_lifetime ; CHECK-NOT: @__safestack_unsafe_stack_ptr ; CHECK: ret void + ; SEP-STK-LABEL: define void @call_lifetime + ; SEP-STK-NOT: @__safestack_unsafe_stack_ptr + ; SEP-STK: ret void entry: %q = alloca [100 x i8], align 16 %0 = bitcast [100 x i8]* %q to i8*