diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -637,6 +637,10 @@ /// returns the address of that location. Otherwise, returns nullptr. Value *getIRStackGuard(IRBuilderBase &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(IRBuilderBase &IRB) const override; + private: /// RISCVCCAssignFn - This target-specific function extends the default /// CCValAssign with additional information used to lower RISC-V calling diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -13269,11 +13269,11 @@ return false; SDNode *Copy = *N->use_begin(); - + if (Copy->getOpcode() == ISD::BITCAST) { return isUsedByReturnOnly(Copy, Chain); } - + // TODO: Handle additional opcodes in order to support tail-calling libcalls // with soft float ABIs. if (Copy->getOpcode() != ISD::CopyToReg) { @@ -14240,6 +14240,15 @@ return TargetLowering::getIRStackGuard(IRB); } +Value *RISCVTargetLowering::getSafeStackPointerLocation(IRBuilderBase &IRB) const { + // Fuchsia provides a fixed TLS slot for the unsafe stack pointer. + // defines ZX_TLS_UNSAFE_SP_OFFSET with this value. + if (Subtarget.isTargetFuchsia()) + return useTpOffset(IRB, -0x8); + + return TargetLowering::getIRStackGuard(IRB); +} + #define GET_REGISTER_MATCHER #include "RISCVGenAsmMatcher.inc" diff --git a/llvm/test/Transforms/SafeStack/RISCV/abi.ll b/llvm/test/Transforms/SafeStack/RISCV/abi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SafeStack/RISCV/abi.ll @@ -0,0 +1,18 @@ +; RUN: opt -safe-stack -S -mtriple=riscv64-fuchsia < %s -o - | FileCheck --check-prefixes=TLS,FUCHSIA %s + +define void @unsafe_stack_escapes() nounwind safestack { +; TLS: %[[TP:.*]] = call ptr @llvm.thread.pointer() +;; Another platform with a different TP offset would use PLATFORM: here. +; FUCHSIA: %[[UnsafeSpPtr:.*]] = getelementptr i8, ptr %[[TP]], i32 -8 +; TLS: %[[OldSp:.*]] = load ptr, ptr %[[UnsafeSpPtr]] +; TLS: %[[NewSp:.*]] = getelementptr i8, ptr %[[OldSp]], i32 -16 +; TLS: store ptr %[[NewSp]], ptr %[[UnsafeSpPtr]] + + %a = alloca i8, align 8 + call void @capture(ptr %a) + +; CHECK: store ptr %[[OldSp]], ptr %[[UnsafeSpPtr]] + ret void +} + +declare void @capture(ptr) diff --git a/llvm/test/Transforms/SafeStack/RISCV/abi_ssp.ll b/llvm/test/Transforms/SafeStack/RISCV/abi_ssp.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SafeStack/RISCV/abi_ssp.ll @@ -0,0 +1,21 @@ +; RUN: opt -safe-stack -S -mtriple=riscv64-fuchsia < %s -o - | FileCheck --check-prefixes=TLS,FUCHSIA %s + +define void @unsafe_stack_escapes() nounwind safestack sspreq { +;; First the TP will be fetched to fetch the USP (tested in abi.ll); skip that. +; TLS: %[[TpForUsp:.*]] = call ptr @llvm.thread.pointer() +;; The second TP fetch will be the one to get the stack guard value. +; TLS: %[[TpForGuard:.*]] = call ptr @llvm.thread.pointer() +;; Another platform with a different TP offset would use PLATFORM: here. +; FUCHSIA: %[[GuardPtr:.*]] = getelementptr i8, ptr %[[TpForGuard]], i32 -16 +; TLS: %[[GuardValue:.*]] = load ptr, ptr %[[GuardPtr]] +; TLS: store ptr %[[GuardValue]], ptr %[[CanarySlot:.*]] + + %a = alloca i8, align 8 + call void @capture(ptr %a) + +; TLS: %[[CanaryValue:.*]] = load ptr, ptr %[[CanarySlot]] +; TLS: icmp ne ptr %[[GuardValue]], %[[CanaryValue]] + ret void +} + +declare void @capture(ptr) diff --git a/llvm/test/Transforms/SafeStack/RISCV/lit.local.cfg b/llvm/test/Transforms/SafeStack/RISCV/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SafeStack/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True