zzheng created this revision.
zzheng added reviewers: apazos, lenary, asb.
Herald added subscribers: cfe-commits, aaron.ballman, evandro, luismarques,
sameer.abuasal, pzheng, s.egerton, Jim, benna, psnobl, jocewei, PkmX, rkruppe,
the_o, brucehoult, MartinMosbeck, rogfer01, edward-jones, MaskRay, jrtc27,
shiva0217, kito-cheng, niosHD, sabuasal, simoncook, johnrusso, rbar, hiraditya,
kristof.beyls.
Herald added projects: clang, LLVM.
Currenlty mimics AArch64's implementation. Assume x18 is used as pointer to
shadow call stack. User shall pass flags:
"-fsanitize=shadow-call-stack -ffixed-x18"
Runtime supported is needed to setup x18.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D84414
Files:
clang/lib/Driver/SanitizerArgs.cpp
clang/lib/Driver/ToolChain.cpp
clang/test/CodeGen/shadowcallstack-attr.c
clang/test/Driver/sanitizer-ld.c
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
llvm/test/CodeGen/RISCV/shadowcallstack.ll
Index: llvm/test/CodeGen/RISCV/shadowcallstack.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/RISCV/shadowcallstack.ll
@@ -0,0 +1,88 @@
+; RUN: llc -verify-machineinstrs -o - %s -mtriple=riscv32-linux-gnu -mattr=+reserve-x18 | FileCheck --check-prefix=RISCV32 %s
+
+; RUN: llc -verify-machineinstrs -o - %s -mtriple=riscv64-linux-gnu -mattr=+reserve-x18 | FileCheck --check-prefix=RISCV64 %s
+
+define void @f1() shadowcallstack {
+ ; CHECK: f1:
+ ; CHECK-NOT: x18
+ ; CHECK: ret
+ ret void
+}
+
+declare void @foo()
+
+define void @f2() shadowcallstack {
+ ; CHECK: f2:
+ ; CHECK-NOT: x18
+ ; CHECK: tail foo
+ tail call void @foo()
+ ret void
+}
+
+declare i32 @bar()
+
+define i32 @f3() shadowcallstack {
+ ; CHECK: f3:
+ ; RISCV32: sw ra, 0(s2)
+ ; RISCV32-NEXT: addi s2, s2, 4
+ ; RISCV64: sw ra, 0(s2)
+ ; RISCV64-NEXT: addi s2, s2, 8
+ ; CHECK: addi sp, sp, -16
+ ; CHECK: sw ra, 12(sp)
+ %res = call i32 @bar()
+ %res1 = add i32 %res, 1
+ ; CHECK: lw ra, 12(sp)
+ ; CHECK: addi sp, sp, 16
+ ; RISCV32: addi s2, s2, -4
+ ; RISCV32-NEXT: lw ra, 0(s2)
+ ; RISCV64: addi s2, s2, -8
+ ; RISCV64-NEXT: lw ra, 0(s2)
+ ; CHECK: ret
+ ret i32 %res
+}
+
+define i32 @f4() shadowcallstack {
+ ; CHECK: f4:
+ ; RISCV32: sw ra, 0(s2)
+ ; RISCV32-NEXT: addi s2, s2, 4
+ ; RISCV64: sw ra, 0(s2)
+ ; RISCV64-NEXT: addi s2, s2, 8
+ ; CHECK: addi sp, sp, -16
+ ; CHECK: sw ra, 12(sp)
+ %res1 = call i32 @bar()
+ %res2 = call i32 @bar()
+ %res3 = call i32 @bar()
+ %res4 = call i32 @bar()
+ %res12 = add i32 %res1, %res2
+ %res34 = add i32 %res3, %res4
+ %res1234 = add i32 %res12, %res34
+ ; CHECK: lw ra, 12(sp)
+ ; CHECK: addi sp, sp, 16
+ ; RISCV32: addi s2, s2, -4
+ ; RISCV32-NEXT: lw ra, 0(s2)
+ ; RISCV64: addi s2, s2, -8
+ ; RISCV64-NEXT: lw ra, 0(s2)
+ ; CHECK: ret
+ ret i32 %res1234
+}
+
+define i32 @f5() shadowcallstack nounwind {
+ ; CHECK: f5:
+ ; CHECK-NOT: .cfi_def_cfa_offset
+ ; RISCV32: sw ra, 0(s2)
+ ; RISCV32-NEXT: addi s2, s2, 4
+ ; RISCV64: sw ra, 0(s2)
+ ; RISCV64-NEXT: addi s2, s2, 8
+ ; CHECK: addi sp, sp, -16
+ ; CHECK: sw ra, 12(sp)
+ %res = call i32 @bar()
+ %res1 = add i32 %res, 1
+ ; CHECK: lw ra, 12(sp)
+ ; CHECK: addi sp, sp, 16
+ ; RISCV32: addi s2, s2, -4
+ ; RISCV32-NEXT: lw ra, 0(s2)
+ ; RISCV64: addi s2, s2, -8
+ ; RISCV64-NEXT: lw ra, 0(s2)
+ ; CHECK: ret
+ ret i32 %res
+}
Index: llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
===================================================================
--- llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -23,6 +23,78 @@
using namespace llvm;
+// For now we use x18, a.k.a s2, as pointer to shadow call stack.
+// User should explicitly set -ffixed-x18 and not use x18 in their asm.
+static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI) {
+ if (!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))
+ return;
+
+ std::vector<CalleeSavedInfo> &CSI = MF.getFrameInfo().getCalleeSavedInfo();
+ if (std::none_of(CSI.begin(), CSI.end(),
+ [] (CalleeSavedInfo &CSR) { return CSR.getReg() == RISCV::X1; }))
+ return;
+
+ const auto &STI = MF.getSubtarget<RISCVSubtarget>();
+ // Emit an error message and bail out.
+ if (!STI.isRegisterReservedByUser(RISCV::X18)) {
+ MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{
+ MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."});
+ return;
+ }
+
+ DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
+
+ const RISCVInstrInfo *TII = STI.getInstrInfo();
+ int64_t SlotSize = STI.getXLen() / 8;
+ // Store return address to shadow call stack
+ // sw ra, 0(s2)
+ // addi s2, s2, 4
+ BuildMI(MBB, MI, DL, TII->get(RISCV::SW))
+ .addReg(RISCV::X1)
+ .addReg(RISCV::X18)
+ .addImm(0);
+ BuildMI(MBB, MI, DL, TII->get(RISCV::ADDI))
+ .addReg(RISCV::X18, RegState::Define)
+ .addReg(RISCV::X18)
+ .addImm(SlotSize);
+}
+
+static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI) {
+ if (!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))
+ return;
+
+ std::vector<CalleeSavedInfo> &CSI = MF.getFrameInfo().getCalleeSavedInfo();
+ if (std::none_of(CSI.begin(), CSI.end(),
+ [] (CalleeSavedInfo &CSR) { return CSR.getReg() == RISCV::X1; }))
+ return;
+
+ const auto &STI = MF.getSubtarget<RISCVSubtarget>();
+ // Emit an error message and bail out.
+ if (!STI.isRegisterReservedByUser(RISCV::X18)) {
+ MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{
+ MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."});
+ return;
+ }
+
+ DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
+
+ const RISCVInstrInfo *TII = STI.getInstrInfo();
+ int64_t SlotSize = STI.getXLen() / 8;
+ // Load return address from shadow call stack
+ // addi s2, s2, -4
+ // lw ra, 0(s2)
+ BuildMI(MBB, MI, DL, TII->get(RISCV::ADDI))
+ .addReg(RISCV::X18, RegState::Define)
+ .addReg(RISCV::X18)
+ .addImm(-SlotSize);
+ BuildMI(MBB, MI, DL, TII->get(RISCV::LW))
+ .addReg(RISCV::X1, RegState::Define)
+ .addReg(RISCV::X18)
+ .addImm(0);
+}
+
// Get the ID of the libcall used for spilling and restoring callee saved
// registers. The ID is representative of the number of registers saved or
// restored by the libcall, except it is zero-indexed - ID 0 corresponds to a
@@ -222,6 +294,9 @@
Register SPReg = getSPReg(STI);
Register BPReg = RISCVABI::getBPReg();
+ // Emit prologue for shadow call stack.
+ emitSCSPrologue(MF, MBB, MBBI);
+
// Since spillCalleeSavedRegisters may have inserted a libcall, skip past
// any instructions marked as FrameSetup
while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
@@ -457,6 +532,9 @@
// Deallocate stack
adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
+
+ // Emit epilogue for shadow call stack.
+ emitSCSEpilogue(MF, MBB, MBBI);
}
int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
Index: clang/test/Driver/sanitizer-ld.c
===================================================================
--- clang/test/Driver/sanitizer-ld.c
+++ clang/test/Driver/sanitizer-ld.c
@@ -615,6 +615,16 @@
// CHECK-SHADOWCALLSTACK-LINUX-AARCH64: '-fsanitize=shadow-call-stack' only allowed with '-ffixed-x18'
// RUN: %clang -fsanitize=shadow-call-stack %s -### -o %t.o 2>&1 \
+// RUN: -target riscv32-unknown-elf -fuse-ld=ld \
+// RUN: | FileCheck --check-prefix=CHECK-SHADOWCALLSTACK-ELF-RISCV32 %s
+// CHECK-SHADOWCALLSTACK-ELF-RISCV32: '-fsanitize=shadow-call-stack' only allowed with '-ffixed-x18'
+
+// RUN: %clang -fsanitize=shadow-call-stack %s -### -o %t.o 2>&1 \
+// RUN: -target riscv64-unknown-linux -fuse-ld=ld \
+// RUN: | FileCheck --check-prefix=CHECK-SHADOWCALLSTACK-LINUX-RISCV64 %s
+// CHECK-SHADOWCALLSTACK-LINUX-RISCV64: '-fsanitize=shadow-call-stack' only allowed with '-ffixed-x18'
+
+// RUN: %clang -fsanitize=shadow-call-stack %s -### -o %t.o 2>&1 \
// RUN: -target aarch64-unknown-linux -fuse-ld=ld -ffixed-x18 \
// RUN: | FileCheck --check-prefix=CHECK-SHADOWCALLSTACK-LINUX-AARCH64-X18 %s
// RUN: %clang -fsanitize=shadow-call-stack %s -### -o %t.o 2>&1 \
Index: clang/test/CodeGen/shadowcallstack-attr.c
===================================================================
--- clang/test/CodeGen/shadowcallstack-attr.c
+++ clang/test/CodeGen/shadowcallstack-attr.c
@@ -5,6 +5,20 @@
// RUN: echo -e "[shadow-call-stack]\nfun:foo" > %t
// RUN: %clang_cc1 -fsanitize-blacklist=%t -triple x86_64-linux-unknown -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLACKLISTED %s
+// RUN: %clang_cc1 -triple riscv32-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=UNBLACKLISTED %s
+
+// RUN: %clang_cc1 -D ATTR -triple riscv32-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLACKLISTED %s
+
+// RUN: echo -e "[shadow-call-stack]\nfun:foo" > %t
+// RUN: %clang_cc1 -fsanitize-blacklist=%t -triple riscv32-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLACKLISTED %s
+
+// RUN: %clang_cc1 -triple riscv64-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=UNBLACKLISTED %s
+
+// RUN: %clang_cc1 -D ATTR -triple riscv64-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLACKLISTED %s
+
+// RUN: echo -e "[shadow-call-stack]\nfun:foo" > %t
+// RUN: %clang_cc1 -fsanitize-blacklist=%t -triple riscv64-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLACKLISTED %s
+
#ifdef ATTR
__attribute__((no_sanitize("shadow-call-stack")))
#endif
Index: clang/lib/Driver/ToolChain.cpp
===================================================================
--- clang/lib/Driver/ToolChain.cpp
+++ clang/lib/Driver/ToolChain.cpp
@@ -1024,7 +1024,8 @@
getTriple().getArch() == llvm::Triple::arm || getTriple().isWasm() ||
getTriple().isAArch64())
Res |= SanitizerKind::CFIICall;
- if (getTriple().getArch() == llvm::Triple::x86_64 || getTriple().isAArch64())
+ if (getTriple().getArch() == llvm::Triple::x86_64 ||
+ getTriple().isAArch64() || getTriple().isRISCV())
Res |= SanitizerKind::ShadowCallStack;
if (getTriple().isAArch64())
Res |= SanitizerKind::MemTag;
Index: clang/lib/Driver/SanitizerArgs.cpp
===================================================================
--- clang/lib/Driver/SanitizerArgs.cpp
+++ clang/lib/Driver/SanitizerArgs.cpp
@@ -491,8 +491,10 @@
<< lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
}
- if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().isAArch64() &&
- !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) &&
+ if ((Kinds & SanitizerKind::ShadowCallStack) &&
+ ((TC.getTriple().isAArch64() &&
+ !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) ||
+ TC.getTriple().isRISCV()) &&
!Args.hasArg(options::OPT_ffixed_x18)) {
D.Diag(diag::err_drv_argument_only_allowed_with)
<< lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack)
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits