[llvm] [clang] [RISCV] Add Zicfiss support to the shadow call stack implementation. (PR #68075)
Yeting Kuo via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 16 18:49:22 PST 2024
https://github.com/yetingk updated https://github.com/llvm/llvm-project/pull/68075
>From faed2ea0b0cd7dc207e0886be8cb1647343793d4 Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Tue, 3 Oct 2023 16:08:06 +0800
Subject: [PATCH 1/8] [RISCV] Implement shadow stack on shadow stack mode with
Zicfiss.
There are two shadow stack implements with Zicfiss in [spec] now.
In Shadow stack mode, programs still store the return address to regular address.
In Control stack mode, programs only store the return address to shadow stack.
This patch only supports the shadow stack mode.
[spec]: https://github.com/riscv/riscv-cfi/blob/main/cfi_backward.adoc#push-to-and-pop-from-the-shadow-stack
---
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 14 +-
llvm/test/CodeGen/RISCV/shadowcallstack.ll | 130 +++++++++++++++++++
2 files changed, 142 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 8dfea6d3862057c..6f043ade98f4093 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -51,9 +51,14 @@ static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
CSI, [&](CalleeSavedInfo &CSR) { return CSR.getReg() == RAReg; }))
return;
+ const RISCVInstrInfo *TII = STI.getInstrInfo();
+ if (STI.hasFeature(RISCV::FeatureStdExtZicfiss)) {
+ BuildMI(MBB, MI, DL, TII->get(RISCV::SSPUSH)).addReg(RAReg);
+ return;
+ }
+
Register SCSPReg = RISCVABI::getSCSPReg();
- const RISCVInstrInfo *TII = STI.getInstrInfo();
bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
int64_t SlotSize = STI.getXLen() / 8;
// Store return address to shadow call stack
@@ -106,9 +111,14 @@ static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB,
CSI, [&](CalleeSavedInfo &CSR) { return CSR.getReg() == RAReg; }))
return;
+ const RISCVInstrInfo *TII = STI.getInstrInfo();
+ if (STI.hasFeature(RISCV::FeatureStdExtZicfiss)) {
+ BuildMI(MBB, MI, DL, TII->get(RISCV::SSPOPCHK)).addReg(RAReg);
+ return;
+ }
+
Register SCSPReg = RISCVABI::getSCSPReg();
- const RISCVInstrInfo *TII = STI.getInstrInfo();
bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
int64_t SlotSize = STI.getXLen() / 8;
// Load return address from shadow call stack
diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
index b41b87aaf4d0d88..1861d2e36227c33 100644
--- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll
+++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
@@ -3,6 +3,10 @@
; RUN: | FileCheck %s --check-prefix=RV32
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
; RUN: | FileCheck %s --check-prefix=RV64
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss -verify-machineinstrs < %s \
+; RUN: | FileCheck %s --check-prefix=RV32-ZICFISS
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss -verify-machineinstrs < %s \
+; RUN: | FileCheck %s --check-prefix=RV64-ZICFISS
define void @f1() shadowcallstack {
; RV32-LABEL: f1:
@@ -12,6 +16,14 @@ define void @f1() shadowcallstack {
; RV64-LABEL: f1:
; RV64: # %bb.0:
; RV64-NEXT: ret
+;
+; RV32-ZICFISS-LABEL: f1:
+; RV32-ZICFISS: # %bb.0:
+; RV32-ZICFISS-NEXT: ret
+;
+; RV64-ZICFISS-LABEL: f1:
+; RV64-ZICFISS: # %bb.0:
+; RV64-ZICFISS-NEXT: ret
ret void
}
@@ -25,6 +37,14 @@ define void @f2() shadowcallstack {
; RV64-LABEL: f2:
; RV64: # %bb.0:
; RV64-NEXT: tail foo
+;
+; RV32-ZICFISS-LABEL: f2:
+; RV32-ZICFISS: # %bb.0:
+; RV32-ZICFISS-NEXT: tail foo
+;
+; RV64-ZICFISS-LABEL: f2:
+; RV64-ZICFISS: # %bb.0:
+; RV64-ZICFISS-NEXT: tail foo
tail call void @foo()
ret void
}
@@ -65,6 +85,32 @@ define i32 @f3() shadowcallstack {
; RV64-NEXT: addi gp, gp, -8
; RV64-NEXT: .cfi_restore gp
; RV64-NEXT: ret
+;
+; RV32-ZICFISS-LABEL: f3:
+; RV32-ZICFISS: # %bb.0:
+; RV32-ZICFISS-NEXT: sspush ra
+; RV32-ZICFISS-NEXT: addi sp, sp, -16
+; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 16
+; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32-ZICFISS-NEXT: .cfi_offset ra, -4
+; RV32-ZICFISS-NEXT: call bar
+; RV32-ZICFISS-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32-ZICFISS-NEXT: addi sp, sp, 16
+; RV32-ZICFISS-NEXT: sspopchk ra
+; RV32-ZICFISS-NEXT: ret
+;
+; RV64-ZICFISS-LABEL: f3:
+; RV64-ZICFISS: # %bb.0:
+; RV64-ZICFISS-NEXT: sspush ra
+; RV64-ZICFISS-NEXT: addi sp, sp, -16
+; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 16
+; RV64-ZICFISS-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64-ZICFISS-NEXT: .cfi_offset ra, -8
+; RV64-ZICFISS-NEXT: call bar
+; RV64-ZICFISS-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64-ZICFISS-NEXT: addi sp, sp, 16
+; RV64-ZICFISS-NEXT: sspopchk ra
+; RV64-ZICFISS-NEXT: ret
%res = call i32 @bar()
%res1 = add i32 %res, 1
ret i32 %res
@@ -140,6 +186,68 @@ define i32 @f4() shadowcallstack {
; RV64-NEXT: addi gp, gp, -8
; RV64-NEXT: .cfi_restore gp
; RV64-NEXT: ret
+;
+; RV32-ZICFISS-LABEL: f4:
+; RV32-ZICFISS: # %bb.0:
+; RV32-ZICFISS-NEXT: sspush ra
+; RV32-ZICFISS-NEXT: addi sp, sp, -16
+; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 16
+; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32-ZICFISS-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
+; RV32-ZICFISS-NEXT: sw s1, 4(sp) # 4-byte Folded Spill
+; RV32-ZICFISS-NEXT: sw s2, 0(sp) # 4-byte Folded Spill
+; RV32-ZICFISS-NEXT: .cfi_offset ra, -4
+; RV32-ZICFISS-NEXT: .cfi_offset s0, -8
+; RV32-ZICFISS-NEXT: .cfi_offset s1, -12
+; RV32-ZICFISS-NEXT: .cfi_offset s2, -16
+; RV32-ZICFISS-NEXT: call bar
+; RV32-ZICFISS-NEXT: mv s0, a0
+; RV32-ZICFISS-NEXT: call bar
+; RV32-ZICFISS-NEXT: mv s1, a0
+; RV32-ZICFISS-NEXT: call bar
+; RV32-ZICFISS-NEXT: mv s2, a0
+; RV32-ZICFISS-NEXT: call bar
+; RV32-ZICFISS-NEXT: add s0, s0, s1
+; RV32-ZICFISS-NEXT: add a0, s2, a0
+; RV32-ZICFISS-NEXT: add a0, s0, a0
+; RV32-ZICFISS-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32-ZICFISS-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
+; RV32-ZICFISS-NEXT: lw s1, 4(sp) # 4-byte Folded Reload
+; RV32-ZICFISS-NEXT: lw s2, 0(sp) # 4-byte Folded Reload
+; RV32-ZICFISS-NEXT: addi sp, sp, 16
+; RV32-ZICFISS-NEXT: sspopchk ra
+; RV32-ZICFISS-NEXT: ret
+;
+; RV64-ZICFISS-LABEL: f4:
+; RV64-ZICFISS: # %bb.0:
+; RV64-ZICFISS-NEXT: sspush ra
+; RV64-ZICFISS-NEXT: addi sp, sp, -32
+; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 32
+; RV64-ZICFISS-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
+; RV64-ZICFISS-NEXT: sd s0, 16(sp) # 8-byte Folded Spill
+; RV64-ZICFISS-NEXT: sd s1, 8(sp) # 8-byte Folded Spill
+; RV64-ZICFISS-NEXT: sd s2, 0(sp) # 8-byte Folded Spill
+; RV64-ZICFISS-NEXT: .cfi_offset ra, -8
+; RV64-ZICFISS-NEXT: .cfi_offset s0, -16
+; RV64-ZICFISS-NEXT: .cfi_offset s1, -24
+; RV64-ZICFISS-NEXT: .cfi_offset s2, -32
+; RV64-ZICFISS-NEXT: call bar
+; RV64-ZICFISS-NEXT: mv s0, a0
+; RV64-ZICFISS-NEXT: call bar
+; RV64-ZICFISS-NEXT: mv s1, a0
+; RV64-ZICFISS-NEXT: call bar
+; RV64-ZICFISS-NEXT: mv s2, a0
+; RV64-ZICFISS-NEXT: call bar
+; RV64-ZICFISS-NEXT: add s0, s0, s1
+; RV64-ZICFISS-NEXT: add a0, s2, a0
+; RV64-ZICFISS-NEXT: addw a0, s0, a0
+; RV64-ZICFISS-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
+; RV64-ZICFISS-NEXT: ld s0, 16(sp) # 8-byte Folded Reload
+; RV64-ZICFISS-NEXT: ld s1, 8(sp) # 8-byte Folded Reload
+; RV64-ZICFISS-NEXT: ld s2, 0(sp) # 8-byte Folded Reload
+; RV64-ZICFISS-NEXT: addi sp, sp, 32
+; RV64-ZICFISS-NEXT: sspopchk ra
+; RV64-ZICFISS-NEXT: ret
%res1 = call i32 @bar()
%res2 = call i32 @bar()
%res3 = call i32 @bar()
@@ -176,6 +284,28 @@ define i32 @f5() shadowcallstack nounwind {
; RV64-NEXT: ld ra, -8(gp)
; RV64-NEXT: addi gp, gp, -8
; RV64-NEXT: ret
+;
+; RV32-ZICFISS-LABEL: f5:
+; RV32-ZICFISS: # %bb.0:
+; RV32-ZICFISS-NEXT: sspush ra
+; RV32-ZICFISS-NEXT: addi sp, sp, -16
+; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32-ZICFISS-NEXT: call bar
+; RV32-ZICFISS-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32-ZICFISS-NEXT: addi sp, sp, 16
+; RV32-ZICFISS-NEXT: sspopchk ra
+; RV32-ZICFISS-NEXT: ret
+;
+; RV64-ZICFISS-LABEL: f5:
+; RV64-ZICFISS: # %bb.0:
+; RV64-ZICFISS-NEXT: sspush ra
+; RV64-ZICFISS-NEXT: addi sp, sp, -16
+; RV64-ZICFISS-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64-ZICFISS-NEXT: call bar
+; RV64-ZICFISS-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64-ZICFISS-NEXT: addi sp, sp, 16
+; RV64-ZICFISS-NEXT: sspopchk ra
+; RV64-ZICFISS-NEXT: ret
%res = call i32 @bar()
%res1 = add i32 %res, 1
ret i32 %res
>From fd1bb8c74055e0319dffac389df314821b2fb8f5 Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Thu, 12 Oct 2023 22:32:34 -0700
Subject: [PATCH 2/8] [ShadowCallStack][RISCV] Update shadow stack doc.
---
clang/docs/ShadowCallStack.rst | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/clang/docs/ShadowCallStack.rst b/clang/docs/ShadowCallStack.rst
index 04c04d259d7dc6f..0785d2fe637926f 100644
--- a/clang/docs/ShadowCallStack.rst
+++ b/clang/docs/ShadowCallStack.rst
@@ -57,11 +57,11 @@ compiled application or the operating system. Integrating the runtime into
the operating system should be preferred since otherwise all thread creation
and destruction would need to be intercepted by the application.
-The instrumentation makes use of the platform register ``x18`` on AArch64 and
-``x3`` (``gp``) on RISC-V. For simplicity we will refer to this as the
-``SCSReg``. On some platforms, ``SCSReg`` is reserved, and on others, it is
-designated as a scratch register. This generally means that any code that may
-run on the same thread as code compiled with ShadowCallStack must either target
+The instrumentation makes use of the platform register ``x18`` on AArch64,
+``x3`` (``gp``) on RISC-V without `Zicfiss`_ and ``ssp`` on RISCV with `Zicfiss`_.
+For simplicity we will refer to this as the ``SCSReg``. On some platforms,
+``SCSReg`` is reserved, and on others, it is designated as a scratch register.
+This generally means that any code that may run on the same thread as code compiled with ShadowCallStack must either target
one of the platforms whose ABI reserves ``SCSReg`` (currently Android, Darwin,
Fuchsia and Windows) or be compiled with a flag to reserve that register (e.g.,
``-ffixed-x18``). If absolutely necessary, code compiled without reserving the
@@ -70,6 +70,7 @@ saving the register value temporarily on the stack (`example in Android`_) but
this should be done with care since it risks leaking the shadow call stack
address.
+.. _`Zicfiss`: https://github.com/riscv/riscv-cfi/blob/main/cfi_backward.adoc
.. _`example in Android`: https://android-review.googlesource.com/c/platform/frameworks/base/+/803717
Because it requires a dedicated register, the ShadowCallStack feature is
@@ -151,9 +152,10 @@ Usage
To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` flag
to both compile and link command lines. On aarch64, you also need to pass
-``-ffixed-x18`` unless your target already reserves ``x18``. On RISC-V, ``x3``
-(``gp``) is always reserved. It is, however, important to disable GP relaxation
-in the linker. This can be done with the ``--no-relax-gp`` flag in GNU ld.
+``-ffixed-x18`` unless your target already reserves ``x18``. On RISC-V without
+`Zicfiss`_, ``x3`` (``gp``) is always reserved. It is, however, important to
+disable GP relaxation in the linker. This can be done with the ``--no-relax-gp``
+flag in GNU ld.
Low-level API
-------------
>From 7ee57c4e282396f80bbe0e944585a41201192d81 Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Mon, 16 Oct 2023 14:11:18 +0800
Subject: [PATCH 3/8] [RISCV] Add option to enable hardware shadow stack.
---
clang/docs/ShadowCallStack.rst | 7 ++++---
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 13 +++++++++++--
llvm/test/CodeGen/RISCV/shadowcallstack.ll | 4 ++--
3 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/clang/docs/ShadowCallStack.rst b/clang/docs/ShadowCallStack.rst
index 0785d2fe637926f..8f9699a2a45d8d5 100644
--- a/clang/docs/ShadowCallStack.rst
+++ b/clang/docs/ShadowCallStack.rst
@@ -58,7 +58,8 @@ the operating system should be preferred since otherwise all thread creation
and destruction would need to be intercepted by the application.
The instrumentation makes use of the platform register ``x18`` on AArch64,
-``x3`` (``gp``) on RISC-V without `Zicfiss`_ and ``ssp`` on RISCV with `Zicfiss`_.
+``x3`` (``gp``) on RISC-V with software shadow stack and ``ssp`` on RISC-V with
+hardware shadow stack, which needs `Zicfiss`_ and ``-mllvm -riscv-hardware-shadow-stack``.
For simplicity we will refer to this as the ``SCSReg``. On some platforms,
``SCSReg`` is reserved, and on others, it is designated as a scratch register.
This generally means that any code that may run on the same thread as code compiled with ShadowCallStack must either target
@@ -152,8 +153,8 @@ Usage
To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` flag
to both compile and link command lines. On aarch64, you also need to pass
-``-ffixed-x18`` unless your target already reserves ``x18``. On RISC-V without
-`Zicfiss`_, ``x3`` (``gp``) is always reserved. It is, however, important to
+``-ffixed-x18`` unless your target already reserves ``x18``. On RISC-V with software
+shadow stack, ``x3`` (``gp``) is always reserved. It is, however, important to
disable GP relaxation in the linker. This can be done with the ``--no-relax-gp``
flag in GNU ld.
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 6f043ade98f4093..aa63418011bc701 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -27,6 +27,11 @@
using namespace llvm;
+static cl::opt<bool>
+ HardwareShadowStack("riscv-hardware-shadow-stack", cl::init(false),
+ cl::Hidden,
+ cl::desc("Enable hardware shadow stack with Zicfiss."));
+
static const Register AllPopRegs[] = {
RISCV::X1, RISCV::X8, RISCV::X9, RISCV::X18, RISCV::X19,
RISCV::X20, RISCV::X21, RISCV::X22, RISCV::X23, RISCV::X24,
@@ -52,7 +57,9 @@ static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
return;
const RISCVInstrInfo *TII = STI.getInstrInfo();
- if (STI.hasFeature(RISCV::FeatureStdExtZicfiss)) {
+ if (HardwareShadowStack) {
+ if (!STI.hasFeature(RISCV::FeatureStdExtZicfiss))
+ report_fatal_error("Hardware shadow stack needs Zicfiss to be enabled");
BuildMI(MBB, MI, DL, TII->get(RISCV::SSPUSH)).addReg(RAReg);
return;
}
@@ -112,7 +119,9 @@ static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB,
return;
const RISCVInstrInfo *TII = STI.getInstrInfo();
- if (STI.hasFeature(RISCV::FeatureStdExtZicfiss)) {
+ if (HardwareShadowStack) {
+ if (!STI.hasFeature(RISCV::FeatureStdExtZicfiss))
+ report_fatal_error("Hardware shadow stack needs Zicfiss to be enabled");
BuildMI(MBB, MI, DL, TII->get(RISCV::SSPOPCHK)).addReg(RAReg);
return;
}
diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
index 1861d2e36227c33..149a59952b6deef 100644
--- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll
+++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
@@ -3,9 +3,9 @@
; RUN: | FileCheck %s --check-prefix=RV32
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
; RUN: | FileCheck %s --check-prefix=RV64
-; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss -verify-machineinstrs < %s \
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss -riscv-hardware-shadow-stack -verify-machineinstrs < %s \
; RUN: | FileCheck %s --check-prefix=RV32-ZICFISS
-; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss -verify-machineinstrs < %s \
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss -riscv-hardware-shadow-stack -verify-machineinstrs < %s \
; RUN: | FileCheck %s --check-prefix=RV64-ZICFISS
define void @f1() shadowcallstack {
>From f99f73ff2d15b25152914b66fe66cdf669d220d6 Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Wed, 1 Nov 2023 00:49:00 +0800
Subject: [PATCH 4/8] [RISCV] Add feature forced-sw-shadow-stack to decide use
hw/sw implemenet for shadow stack.
---
llvm/lib/Target/RISCV/RISCVFeatures.td | 5 +++++
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 15 ++++-----------
llvm/test/CodeGen/RISCV/shadowcallstack.ll | 12 ++++++++----
3 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 59b202606dadaff..6520cc547502200 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1044,3 +1044,8 @@ def FeatureTaggedGlobals : SubtargetFeature<"tagged-globals",
"AllowTaggedGlobals",
"true", "Use an instruction sequence for taking the address of a global "
"that allows a memory tag in the upper address bits">;
+
+def FeatureForcedSWShadowStack : SubtargetFeature<
+ "forced-sw-shadow-stack", "HasForcedSWShadowStack", "true",
+ "Implement shadow stack with software.">;
+def HasForcedSWShadowStack : Predicate<"Subtarget->hasForcedSWShadowStack()">;
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index aa63418011bc701..98cc5025c320d59 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -27,11 +27,6 @@
using namespace llvm;
-static cl::opt<bool>
- HardwareShadowStack("riscv-hardware-shadow-stack", cl::init(false),
- cl::Hidden,
- cl::desc("Enable hardware shadow stack with Zicfiss."));
-
static const Register AllPopRegs[] = {
RISCV::X1, RISCV::X8, RISCV::X9, RISCV::X18, RISCV::X19,
RISCV::X20, RISCV::X21, RISCV::X22, RISCV::X23, RISCV::X24,
@@ -57,9 +52,8 @@ static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
return;
const RISCVInstrInfo *TII = STI.getInstrInfo();
- if (HardwareShadowStack) {
- if (!STI.hasFeature(RISCV::FeatureStdExtZicfiss))
- report_fatal_error("Hardware shadow stack needs Zicfiss to be enabled");
+ if (!STI.hasForcedSWShadowStack() &&
+ STI.hasFeature(RISCV::FeatureStdExtZicfiss)) {
BuildMI(MBB, MI, DL, TII->get(RISCV::SSPUSH)).addReg(RAReg);
return;
}
@@ -119,9 +113,8 @@ static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB,
return;
const RISCVInstrInfo *TII = STI.getInstrInfo();
- if (HardwareShadowStack) {
- if (!STI.hasFeature(RISCV::FeatureStdExtZicfiss))
- report_fatal_error("Hardware shadow stack needs Zicfiss to be enabled");
+ if (!STI.hasForcedSWShadowStack() &&
+ STI.hasFeature(RISCV::FeatureStdExtZicfiss)) {
BuildMI(MBB, MI, DL, TII->get(RISCV::SSPOPCHK)).addReg(RAReg);
return;
}
diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
index 149a59952b6deef..a320b44d2c6a81d 100644
--- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll
+++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
@@ -3,10 +3,14 @@
; RUN: | FileCheck %s --check-prefix=RV32
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
; RUN: | FileCheck %s --check-prefix=RV64
-; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss -riscv-hardware-shadow-stack -verify-machineinstrs < %s \
-; RUN: | FileCheck %s --check-prefix=RV32-ZICFISS
-; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss -riscv-hardware-shadow-stack -verify-machineinstrs < %s \
-; RUN: | FileCheck %s --check-prefix=RV64-ZICFISS
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss < %s \
+; RUN: -verify-machineinstrs | FileCheck %s --check-prefix=RV32-ZICFISS
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss < %s \
+; RUN: -verify-machineinstrs | FileCheck %s --check-prefix=RV64-ZICFISS
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss,forced-sw-shadow-stack \
+; RUN: -verify-machineinstrs < %s | FileCheck %s --check-prefix=RV32
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss,forced-sw-shadow-stack \
+; RUN: -verify-machineinstrs < %s | FileCheck %s --check-prefix=RV64
define void @f1() shadowcallstack {
; RV32-LABEL: f1:
>From 82411aa9c17c8987e885673cbb1b851475628fde Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Fri, 5 Jan 2024 13:28:46 +0800
Subject: [PATCH 5/8] Add option -{m,mno}-forced-sw-shadow-stack
---
clang/docs/ShadowCallStack.rst | 4 +++-
clang/include/clang/Driver/Options.td | 4 ++++
clang/test/Driver/riscv-features.c | 5 +++++
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/clang/docs/ShadowCallStack.rst b/clang/docs/ShadowCallStack.rst
index 8f9699a2a45d8d5..89c7c9b4180fc88 100644
--- a/clang/docs/ShadowCallStack.rst
+++ b/clang/docs/ShadowCallStack.rst
@@ -59,7 +59,9 @@ and destruction would need to be intercepted by the application.
The instrumentation makes use of the platform register ``x18`` on AArch64,
``x3`` (``gp``) on RISC-V with software shadow stack and ``ssp`` on RISC-V with
-hardware shadow stack, which needs `Zicfiss`_ and ``-mllvm -riscv-hardware-shadow-stack``.
+hardware shadow stack, which needs `Zicfiss`_ and ``-mno-forced-sw-shadow-stack``
+(default option). ``-mforced-sw-shadow-stack`` make risc-v backend generate
+software shadow stack with `Zicfiss`_ when shadow stack enabled.
For simplicity we will refer to this as the ``SCSReg``. On some platforms,
``SCSReg`` is reserved, and on others, it is designated as a scratch register.
This generally means that any code that may run on the same thread as code compiled with ShadowCallStack must either target
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6aff37f1336871c..3a55d1c64341915 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4578,6 +4578,10 @@ def msave_restore : Flag<["-"], "msave-restore">, Group<m_riscv_Features_Group>,
HelpText<"Enable using library calls for save and restore">;
def mno_save_restore : Flag<["-"], "mno-save-restore">, Group<m_riscv_Features_Group>,
HelpText<"Disable using library calls for save and restore">;
+def mforced_sw_shadow_stack : Flag<["-"], "mforced-sw-shadow-stack">, Group<m_riscv_Features_Group>,
+ HelpText<"Force using software shadow stack when shadow-stack enabled">;
+def mno_forced_sw_shadow_stack : Flag<["-"], "mno-forced-sw-shadow-stack">, Group<m_riscv_Features_Group>,
+ HelpText<"Not force using software shadow stack when shadow-stack enabled">;
} // let Flags = [TargetSpecific]
let Flags = [TargetSpecific] in {
def menable_experimental_extensions : Flag<["-"], "menable-experimental-extensions">, Group<m_Group>,
diff --git a/clang/test/Driver/riscv-features.c b/clang/test/Driver/riscv-features.c
index d3700f71aa7e1de..7096895253c386a 100644
--- a/clang/test/Driver/riscv-features.c
+++ b/clang/test/Driver/riscv-features.c
@@ -27,6 +27,11 @@
// DEFAULT-NOT: "-target-feature" "-save-restore"
// DEFAULT-NOT: "-target-feature" "+save-restore"
+// RUN: %clang --target=riscv32-unknown-elf -### %s -mforced-sw-shadow-stack 2>&1 | FileCheck %s -check-prefix=FORCE-SW-SCS
+// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-forced-sw-shadow-stack 2>&1 | FileCheck %s -check-prefix=NO-FORCE-SW-SCS
+// FORCE-SW-SCS: "-target-feature" "+forced-sw-shadow-stack"
+// NO-FORCE-SW-SCS: "-target-feature" "-forced-sw-shadow-stack"
+
// RUN: %clang --target=riscv32-unknown-elf -### %s -munaligned-access 2>&1 | FileCheck %s -check-prefix=FAST-UNALIGNED-ACCESS
// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-unaligned-access 2>&1 | FileCheck %s -check-prefix=NO-FAST-UNALIGNED-ACCESS
// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-strict-align 2>&1 | FileCheck %s -check-prefix=FAST-UNALIGNED-ACCESS
>From 8c3bbce4bbd6a0e271cdb90ec57aecebdbcb44a5 Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Mon, 8 Jan 2024 13:19:40 +0800
Subject: [PATCH 6/8] Refine document.
---
clang/docs/ShadowCallStack.rst | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/clang/docs/ShadowCallStack.rst b/clang/docs/ShadowCallStack.rst
index 89c7c9b4180fc88..e084a96475669bf 100644
--- a/clang/docs/ShadowCallStack.rst
+++ b/clang/docs/ShadowCallStack.rst
@@ -60,8 +60,10 @@ and destruction would need to be intercepted by the application.
The instrumentation makes use of the platform register ``x18`` on AArch64,
``x3`` (``gp``) on RISC-V with software shadow stack and ``ssp`` on RISC-V with
hardware shadow stack, which needs `Zicfiss`_ and ``-mno-forced-sw-shadow-stack``
-(default option). ``-mforced-sw-shadow-stack`` make risc-v backend generate
-software shadow stack with `Zicfiss`_ when shadow stack enabled.
+(default option). Note that with ``Zicfiss``_ the RISC-V backend will default to
+the hardware based shadow call stack. Users can force the RISC-V backend to
+generate the software shadow call stack with ``Zicfiss``_ by passing
+``-mforced-sw-shadow-stack``.
For simplicity we will refer to this as the ``SCSReg``. On some platforms,
``SCSReg`` is reserved, and on others, it is designated as a scratch register.
This generally means that any code that may run on the same thread as code compiled with ShadowCallStack must either target
@@ -155,10 +157,12 @@ Usage
To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` flag
to both compile and link command lines. On aarch64, you also need to pass
-``-ffixed-x18`` unless your target already reserves ``x18``. On RISC-V with software
-shadow stack, ``x3`` (``gp``) is always reserved. It is, however, important to
-disable GP relaxation in the linker. This can be done with the ``--no-relax-gp``
-flag in GNU ld.
+``-ffixed-x18`` unless your target already reserves ``x18``. No additional flags
+need to be passed on RISC-V because the software based shadow stack uses ``x3`` (``gp``),
+which is always reserved, and the hardware based shadow call stack uses a dedicated register, ``ssp``.
+However, it is important to disable GP relaxation in the linker when using the
+software based shadow call stack on RISC-V. This can be done with the
+``--no-relax-gp`` flag in GNU ld, and is off by default in LLD.
Low-level API
-------------
>From faa676804c7eeb296a6173f63a3ac5dc07e3d95b Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Wed, 17 Jan 2024 10:46:28 +0800
Subject: [PATCH 7/8] Make lines less <= 80 chars in
clang/docs/ShadowCallStack.rst
---
clang/docs/ShadowCallStack.rst | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/clang/docs/ShadowCallStack.rst b/clang/docs/ShadowCallStack.rst
index e084a96475669bf..0219674e783c17b 100644
--- a/clang/docs/ShadowCallStack.rst
+++ b/clang/docs/ShadowCallStack.rst
@@ -66,14 +66,14 @@ generate the software shadow call stack with ``Zicfiss``_ by passing
``-mforced-sw-shadow-stack``.
For simplicity we will refer to this as the ``SCSReg``. On some platforms,
``SCSReg`` is reserved, and on others, it is designated as a scratch register.
-This generally means that any code that may run on the same thread as code compiled with ShadowCallStack must either target
-one of the platforms whose ABI reserves ``SCSReg`` (currently Android, Darwin,
-Fuchsia and Windows) or be compiled with a flag to reserve that register (e.g.,
-``-ffixed-x18``). If absolutely necessary, code compiled without reserving the
-register may be run on the same thread as code that uses ShadowCallStack by
-saving the register value temporarily on the stack (`example in Android`_) but
-this should be done with care since it risks leaking the shadow call stack
-address.
+This generally means that any code that may run on the same thread as code
+compiled with ShadowCallStack must either target one of the platforms whose ABI
+reserves ``SCSReg`` (currently Android, Darwin, Fuchsia and Windows) or be
+compiled with a flag to reserve that register (e.g., ``-ffixed-x18``). If
+absolutely necessary, code compiled without reserving the register may be run on
+the same thread as code that uses ShadowCallStack by saving the register value
+temporarily on the stack (`example in Android`_) but this should be done with
+care since it risks leaking the shadow call stack address.
.. _`Zicfiss`: https://github.com/riscv/riscv-cfi/blob/main/cfi_backward.adoc
.. _`example in Android`: https://android-review.googlesource.com/c/platform/frameworks/base/+/803717
@@ -158,8 +158,9 @@ Usage
To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` flag
to both compile and link command lines. On aarch64, you also need to pass
``-ffixed-x18`` unless your target already reserves ``x18``. No additional flags
-need to be passed on RISC-V because the software based shadow stack uses ``x3`` (``gp``),
-which is always reserved, and the hardware based shadow call stack uses a dedicated register, ``ssp``.
+need to be passed on RISC-V because the software based shadow stack uses
+``x3`` (``gp``), which is always reserved, and the hardware based shadow call
+stack uses a dedicated register, ``ssp``.
However, it is important to disable GP relaxation in the linker when using the
software based shadow call stack on RISC-V. This can be done with the
``--no-relax-gp`` flag in GNU ld, and is off by default in LLD.
>From eced3d8d3d64ff25b2669f6d1087d25893fe8021 Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Wed, 17 Jan 2024 10:48:45 +0800
Subject: [PATCH 8/8] Add default test for forced-sw-shadow-stack
---
clang/test/Driver/riscv-features.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/test/Driver/riscv-features.c b/clang/test/Driver/riscv-features.c
index 7096895253c386a..a108383e29fb6be 100644
--- a/clang/test/Driver/riscv-features.c
+++ b/clang/test/Driver/riscv-features.c
@@ -31,6 +31,7 @@
// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-forced-sw-shadow-stack 2>&1 | FileCheck %s -check-prefix=NO-FORCE-SW-SCS
// FORCE-SW-SCS: "-target-feature" "+forced-sw-shadow-stack"
// NO-FORCE-SW-SCS: "-target-feature" "-forced-sw-shadow-stack"
+// DEFAULT-NOT: "-target-feature" "+forced-sw-shadow-stack"
// RUN: %clang --target=riscv32-unknown-elf -### %s -munaligned-access 2>&1 | FileCheck %s -check-prefix=FAST-UNALIGNED-ACCESS
// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-unaligned-access 2>&1 | FileCheck %s -check-prefix=NO-FAST-UNALIGNED-ACCESS
More information about the cfe-commits
mailing list