zzheng updated this revision to Diff 292378.
zzheng marked 2 inline comments as done.
zzheng added a comment.

Fixed comment and lint


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84414/new/

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/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp
  llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h
  llvm/test/CodeGen/RISCV/shadowcallstack.ll

Index: llvm/test/CodeGen/RISCV/shadowcallstack.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/RISCV/shadowcallstack.ll
@@ -0,0 +1,174 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+reserve-x18 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=RV32
+; RUN: llc -mtriple=riscv64 -mattr=+reserve-x18 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=RV64
+
+define void @f1() shadowcallstack {
+; RV32-LABEL: f1:
+; RV32:       # %bb.0:
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: f1:
+; RV64:       # %bb.0:
+; RV64-NEXT:    ret
+  ret void
+}
+
+declare void @foo()
+
+define void @f2() shadowcallstack {
+; RV32-LABEL: f2:
+; RV32:       # %bb.0:
+; RV32-NEXT:    tail foo
+;
+; RV64-LABEL: f2:
+; RV64:       # %bb.0:
+; RV64-NEXT:    tail foo
+  tail call void @foo()
+  ret void
+}
+
+declare i32 @bar()
+
+define i32 @f3() shadowcallstack {
+; RV32-LABEL: f3:
+; RV32:       # %bb.0:
+; RV32-NEXT:    sw ra, 0(s2)
+; RV32-NEXT:    addi s2, s2, 4
+; RV32-NEXT:    addi sp, sp, -16
+; RV32-NEXT:    .cfi_def_cfa_offset 16
+; RV32-NEXT:    sw ra, 12(sp)
+; RV32-NEXT:    .cfi_offset ra, -4
+; RV32-NEXT:    call bar
+; RV32-NEXT:    lw ra, 12(sp)
+; RV32-NEXT:    addi sp, sp, 16
+; RV32-NEXT:    lw ra, -4(s2)
+; RV32-NEXT:    addi s2, s2, -4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: f3:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sd ra, 0(s2)
+; RV64-NEXT:    addi s2, s2, 8
+; RV64-NEXT:    addi sp, sp, -16
+; RV64-NEXT:    .cfi_def_cfa_offset 16
+; RV64-NEXT:    sd ra, 8(sp)
+; RV64-NEXT:    .cfi_offset ra, -8
+; RV64-NEXT:    call bar
+; RV64-NEXT:    ld ra, 8(sp)
+; RV64-NEXT:    addi sp, sp, 16
+; RV64-NEXT:    ld ra, -8(s2)
+; RV64-NEXT:    addi s2, s2, -8
+; RV64-NEXT:    ret
+  %res = call i32 @bar()
+  %res1 = add i32 %res, 1
+  ret i32 %res
+}
+
+define i32 @f4() shadowcallstack {
+; RV32-LABEL: f4:
+; RV32:       # %bb.0:
+; RV32-NEXT:    sw ra, 0(s2)
+; RV32-NEXT:    addi s2, s2, 4
+; RV32-NEXT:    addi sp, sp, -16
+; RV32-NEXT:    .cfi_def_cfa_offset 16
+; RV32-NEXT:    sw ra, 12(sp)
+; RV32-NEXT:    sw s0, 8(sp)
+; RV32-NEXT:    sw s1, 4(sp)
+; RV32-NEXT:    sw s3, 0(sp)
+; RV32-NEXT:    .cfi_offset ra, -4
+; RV32-NEXT:    .cfi_offset s0, -8
+; RV32-NEXT:    .cfi_offset s1, -12
+; RV32-NEXT:    .cfi_offset s3, -16
+; RV32-NEXT:    call bar
+; RV32-NEXT:    mv s3, a0
+; RV32-NEXT:    call bar
+; RV32-NEXT:    mv s1, a0
+; RV32-NEXT:    call bar
+; RV32-NEXT:    mv s0, a0
+; RV32-NEXT:    call bar
+; RV32-NEXT:    add a1, s3, s1
+; RV32-NEXT:    add a0, s0, a0
+; RV32-NEXT:    add a0, a1, a0
+; RV32-NEXT:    lw s3, 0(sp)
+; RV32-NEXT:    lw s1, 4(sp)
+; RV32-NEXT:    lw s0, 8(sp)
+; RV32-NEXT:    lw ra, 12(sp)
+; RV32-NEXT:    addi sp, sp, 16
+; RV32-NEXT:    lw ra, -4(s2)
+; RV32-NEXT:    addi s2, s2, -4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: f4:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sd ra, 0(s2)
+; RV64-NEXT:    addi s2, s2, 8
+; RV64-NEXT:    addi sp, sp, -32
+; RV64-NEXT:    .cfi_def_cfa_offset 32
+; RV64-NEXT:    sd ra, 24(sp)
+; RV64-NEXT:    sd s0, 16(sp)
+; RV64-NEXT:    sd s1, 8(sp)
+; RV64-NEXT:    sd s3, 0(sp)
+; RV64-NEXT:    .cfi_offset ra, -8
+; RV64-NEXT:    .cfi_offset s0, -16
+; RV64-NEXT:    .cfi_offset s1, -24
+; RV64-NEXT:    .cfi_offset s3, -32
+; RV64-NEXT:    call bar
+; RV64-NEXT:    mv s3, a0
+; RV64-NEXT:    call bar
+; RV64-NEXT:    mv s1, a0
+; RV64-NEXT:    call bar
+; RV64-NEXT:    mv s0, a0
+; RV64-NEXT:    call bar
+; RV64-NEXT:    add a1, s3, s1
+; RV64-NEXT:    add a0, s0, a0
+; RV64-NEXT:    addw a0, a1, a0
+; RV64-NEXT:    ld s3, 0(sp)
+; RV64-NEXT:    ld s1, 8(sp)
+; RV64-NEXT:    ld s0, 16(sp)
+; RV64-NEXT:    ld ra, 24(sp)
+; RV64-NEXT:    addi sp, sp, 32
+; RV64-NEXT:    ld ra, -8(s2)
+; RV64-NEXT:    addi s2, s2, -8
+; RV64-NEXT:    ret
+  %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
+  ret i32 %res1234
+}
+
+define i32 @f5() shadowcallstack nounwind {
+; RV32-LABEL: f5:
+; RV32:       # %bb.0:
+; RV32-NEXT:    sw ra, 0(s2)
+; RV32-NEXT:    addi s2, s2, 4
+; RV32-NEXT:    addi sp, sp, -16
+; RV32-NEXT:    sw ra, 12(sp)
+; RV32-NEXT:    call bar
+; RV32-NEXT:    lw ra, 12(sp)
+; RV32-NEXT:    addi sp, sp, 16
+; RV32-NEXT:    lw ra, -4(s2)
+; RV32-NEXT:    addi s2, s2, -4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: f5:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sd ra, 0(s2)
+; RV64-NEXT:    addi s2, s2, 8
+; RV64-NEXT:    addi sp, sp, -16
+; RV64-NEXT:    sd ra, 8(sp)
+; RV64-NEXT:    call bar
+; RV64-NEXT:    ld ra, 8(sp)
+; RV64-NEXT:    addi sp, sp, 16
+; RV64-NEXT:    ld ra, -8(s2)
+; RV64-NEXT:    addi s2, s2, -8
+; RV64-NEXT:    ret
+  %res = call i32 @bar()
+  %res1 = add i32 %res, 1
+  ret i32 %res
+}
Index: llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h
===================================================================
--- llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h
+++ llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h
@@ -208,6 +208,9 @@
 // Returns the register used to hold the stack pointer after realignment.
 Register getBPReg();
 
+// Returns the register holding shadow call stack pointer.
+Register getSCSPReg();
+
 } // namespace RISCVABI
 
 namespace RISCVFeatures {
Index: llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp
===================================================================
--- llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp
+++ llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.cpp
@@ -67,6 +67,9 @@
 // saved registers and X8 will be used as fp. So we choose X9 as bp.
 Register getBPReg() { return RISCV::X9; }
 
+// Returns the register holding shadow call stack pointer.
+Register getSCSPReg() { return RISCV::X18; }
+
 } // namespace RISCVABI
 
 namespace RISCVFeatures {
Index: llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
===================================================================
--- llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -23,6 +23,105 @@
 
 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,
+                            const DebugLoc &DL) {
+  if (!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))
+    return;
+
+  const auto &STI = MF.getSubtarget<RISCVSubtarget>();
+  Register RAReg = STI.getRegisterInfo()->getRARegister();
+
+  // Do not save RA to the SCS if it's not saved to the regular stack,
+  // i.e. RA is not at risk of being overwritten.
+  std::vector<CalleeSavedInfo> &CSI = MF.getFrameInfo().getCalleeSavedInfo();
+  if (std::none_of(CSI.begin(), CSI.end(),
+                   [&](CalleeSavedInfo &CSR) { return CSR.getReg() == RAReg; }))
+    return;
+
+  Register SCSPReg = RISCVABI::getSCSPReg();
+
+  auto &Ctx = MF.getFunction().getContext();
+  if (!STI.isRegisterReservedByUser(SCSPReg)) {
+    Ctx.diagnose(DiagnosticInfoUnsupported{
+        MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."});
+    return;
+  }
+
+  const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
+  if (RVFI->useSaveRestoreLibCalls(MF)) {
+    Ctx.diagnose(DiagnosticInfoUnsupported{
+        MF.getFunction(),
+        "Shadow Call Stack cannot be combined with Save/Restore LibCalls."});
+    return;
+  }
+
+  const RISCVInstrInfo *TII = STI.getInstrInfo();
+  bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
+  int64_t SlotSize = STI.getXLen() / 8;
+  // Store return address to shadow call stack
+  // s[w|d]  ra, 0(s2)
+  // addi    s2, s2, [4|8]
+  BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::SD : RISCV::SW))
+      .addReg(RAReg)
+      .addReg(SCSPReg)
+      .addImm(0);
+  BuildMI(MBB, MI, DL, TII->get(RISCV::ADDI))
+      .addReg(SCSPReg, RegState::Define)
+      .addReg(SCSPReg)
+      .addImm(SlotSize);
+}
+
+static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB,
+                            MachineBasicBlock::iterator MI,
+                            const DebugLoc &DL) {
+  if (!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))
+    return;
+
+  const auto &STI = MF.getSubtarget<RISCVSubtarget>();
+  Register RAReg = STI.getRegisterInfo()->getRARegister();
+
+  // See emitSCSPrologue() above.
+  std::vector<CalleeSavedInfo> &CSI = MF.getFrameInfo().getCalleeSavedInfo();
+  if (std::none_of(CSI.begin(), CSI.end(),
+                   [&](CalleeSavedInfo &CSR) { return CSR.getReg() == RAReg; }))
+    return;
+
+  Register SCSPReg = RISCVABI::getSCSPReg();
+
+  auto &Ctx = MF.getFunction().getContext();
+  if (!STI.isRegisterReservedByUser(SCSPReg)) {
+    Ctx.diagnose(DiagnosticInfoUnsupported{
+        MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."});
+    return;
+  }
+
+  const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
+  if (RVFI->useSaveRestoreLibCalls(MF)) {
+    Ctx.diagnose(DiagnosticInfoUnsupported{
+        MF.getFunction(),
+        "Shadow Call Stack cannot be combined with Save/Restore LibCalls."});
+    return;
+  }
+
+  const RISCVInstrInfo *TII = STI.getInstrInfo();
+  bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
+  int64_t SlotSize = STI.getXLen() / 8;
+  // Load return address from shadow call stack
+  // l[w|d]  ra, -[4|8](s2)
+  // addi    s2, s2, -[4|8]
+  BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::LD : RISCV::LW))
+      .addReg(RAReg, RegState::Define)
+      .addReg(SCSPReg)
+      .addImm(-SlotSize);
+  BuildMI(MBB, MI, DL, TII->get(RISCV::ADDI))
+      .addReg(SCSPReg, RegState::Define)
+      .addReg(SCSPReg)
+      .addImm(-SlotSize);
+}
+
 // 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,15 +321,18 @@
   Register SPReg = getSPReg(STI);
   Register BPReg = RISCVABI::getBPReg();
 
+  // Debug location must be unknown since the first debug location is used
+  // to determine the end of the prologue.
+  DebugLoc DL;
+
+  // Emit prologue for shadow call stack.
+  emitSCSPrologue(MF, MBB, MBBI, DL);
+
   // Since spillCalleeSavedRegisters may have inserted a libcall, skip past
   // any instructions marked as FrameSetup
   while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
     ++MBBI;
 
-  // Debug location must be unknown since the first debug location is used
-  // to determine the end of the prologue.
-  DebugLoc DL;
-
   // Determine the correct frame layout
   determineFrameLayout(MF);
 
@@ -457,6 +559,9 @@
 
   // Deallocate stack
   adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
+
+  // Emit epilogue for shadow call stack.
+  emitSCSEpilogue(MF, MBB, MBBI, DL);
 }
 
 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
@@ -1,9 +1,23 @@
-// RUN: %clang_cc1 -triple x86_64-linux-unknown -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=UNBLACKLISTED %s
+// RUN: %clang_cc1 -triple x86_64-linux-unknown -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=UNBLOCKLISTED %s
 
-// RUN: %clang_cc1 -D ATTR -triple x86_64-linux-unknown -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLACKLISTED %s
+// RUN: %clang_cc1 -D ATTR -triple x86_64-linux-unknown -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLOCKLISTED %s
 
 // 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 -fsanitize-blacklist=%t -triple x86_64-linux-unknown -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLOCKLISTED %s
+
+// RUN: %clang_cc1 -triple riscv32-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=UNBLOCKLISTED %s
+
+// RUN: %clang_cc1 -D ATTR -triple riscv32-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLOCKLISTED %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=BLOCKLISTED %s
+
+// RUN: %clang_cc1 -triple riscv64-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=UNBLOCKLISTED %s
+
+// RUN: %clang_cc1 -D ATTR -triple riscv64-linux-gnu -emit-llvm -o - %s -fsanitize=shadow-call-stack | FileCheck -check-prefix=BLOCKLISTED %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=BLOCKLISTED %s
 
 #ifdef ATTR
 __attribute__((no_sanitize("shadow-call-stack")))
@@ -12,5 +26,5 @@
 
 // CHECK: define i32 @foo(i32* %a)
 
-// BLACKLISTED-NOT: attributes {{.*}}shadowcallstack{{.*}}
-// UNBLACKLISTED: attributes {{.*}}shadowcallstack{{.*}}
+// BLOCKLISTED-NOT: attributes {{.*}}shadowcallstack{{.*}}
+// UNBLOCKLISTED: attributes {{.*}}shadowcallstack{{.*}}
Index: clang/lib/Driver/ToolChain.cpp
===================================================================
--- clang/lib/Driver/ToolChain.cpp
+++ clang/lib/Driver/ToolChain.cpp
@@ -1029,7 +1029,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
@@ -495,8 +495,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