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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to