Skip to content

[clang][RISCV] Introduce preprocessor macro when Zicfiss-based shadow stack is enabled #127592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 18, 2025

Conversation

mylai-mtk
Copy link
Contributor

The -fcf-protection=[full|return] flag enables shadow stack implementation based on RISC-V Zicfiss extension. This patch adds the __riscv_shadow_stack predefined macro to preprocessing when such a shadow stack implementation is enabled.

… stack is enabled

The `-fcf-protection=[full|return]` flag enables shadow stack implementation
based on RISC-V Zicfiss extension. This patch adds the `__riscv_shadow_stack`
predefined macro to preprocessing when such a shadow stack implementation is
enabled.
@mylai-mtk mylai-mtk requested a review from kito-cheng February 18, 2025 08:24
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Feb 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 18, 2025

@llvm/pr-subscribers-clang

Author: Ming-Yi Lai (mylai-mtk)

Changes

The -fcf-protection=[full|return] flag enables shadow stack implementation based on RISC-V Zicfiss extension. This patch adds the __riscv_shadow_stack predefined macro to preprocessing when such a shadow stack implementation is enabled.


Full diff: https://github.com/llvm/llvm-project/pull/127592.diff

4 Files Affected:

  • (modified) clang/include/clang/Basic/LangOptions.def (+1)
  • (modified) clang/lib/Basic/Targets/RISCV.cpp (+3)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+6-1)
  • (added) clang/test/Preprocessor/riscv-cf-protection-return.c (+44)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index bfab0baa089cf..383440ddbc0ea 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -365,6 +365,7 @@ LANGOPT(ObjCDisableDirectMethodsForTesting, 1, 0,
 LANGOPT(CFProtectionBranch , 1, 0, "Control-Flow Branch Protection enabled")
 ENUM_LANGOPT(CFBranchLabelScheme, CFBranchLabelSchemeKind, 2, CFBranchLabelSchemeKind::Default,
              "Control-Flow Branch Protection Label Scheme")
+LANGOPT(CFProtectionReturn, 1, 0, "Control-Flow Return Protection enabled")
 LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
 ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
 LANGOPT(IncludeDefaultHeader, 1, 0, "Include default header file for OpenCL")
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index b4aa3206fcfab..dff990d15dd62 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -238,6 +238,9 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
     else
       Builder.defineMacro("__riscv_32e");
   }
+
+  if (Opts.CFProtectionReturn && ISAInfo->hasExtension("zicfiss"))
+    Builder.defineMacro("__riscv_shadow_stack");
 }
 
 static constexpr int NumRVVBuiltins =
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 014e629c959e2..b9a5c0589ebc4 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -4048,8 +4048,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
 
   if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
     StringRef Name = A->getValue();
-    if (Name == "full" || Name == "branch") {
+    if (Name == "full") {
+      Opts.CFProtectionBranch = 1;
+      Opts.CFProtectionReturn = 1;
+    } else if (Name == "branch") {
       Opts.CFProtectionBranch = 1;
+    } else if (Name == "return") {
+      Opts.CFProtectionReturn = 1;
     }
   }
 
diff --git a/clang/test/Preprocessor/riscv-cf-protection-return.c b/clang/test/Preprocessor/riscv-cf-protection-return.c
new file mode 100644
index 0000000000000..3a93a88fa6839
--- /dev/null
+++ b/clang/test/Preprocessor/riscv-cf-protection-return.c
@@ -0,0 +1,44 @@
+// RUN: %clang --target=riscv32 -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -fcf-protection=return -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -fcf-protection=full -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -march=rv32i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -march=rv32i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=return -E -dM %s \
+// RUN: -o - | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// RUN: %clang --target=riscv32 -march=rv32i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=full -E -dM %s -o - \
+// RUN: | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// RUN: %clang --target=riscv64 -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -fcf-protection=return -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -fcf-protection=full -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -march=rv64i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -march=rv64i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=return -E -dM %s \
+// RUN: -o - | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// RUN: %clang --target=riscv64 -march=rv64i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=full -E -dM %s -o - \
+// RUN: | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// SHSTK-MACRO: __riscv_shadow_stack 1{{$}}
+// NO-MACRO-NOT: __riscv_shadow_stack

@llvmbot
Copy link
Member

llvmbot commented Feb 18, 2025

@llvm/pr-subscribers-backend-risc-v

Author: Ming-Yi Lai (mylai-mtk)

Changes

The -fcf-protection=[full|return] flag enables shadow stack implementation based on RISC-V Zicfiss extension. This patch adds the __riscv_shadow_stack predefined macro to preprocessing when such a shadow stack implementation is enabled.


Full diff: https://github.com/llvm/llvm-project/pull/127592.diff

4 Files Affected:

  • (modified) clang/include/clang/Basic/LangOptions.def (+1)
  • (modified) clang/lib/Basic/Targets/RISCV.cpp (+3)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+6-1)
  • (added) clang/test/Preprocessor/riscv-cf-protection-return.c (+44)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index bfab0baa089cf..383440ddbc0ea 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -365,6 +365,7 @@ LANGOPT(ObjCDisableDirectMethodsForTesting, 1, 0,
 LANGOPT(CFProtectionBranch , 1, 0, "Control-Flow Branch Protection enabled")
 ENUM_LANGOPT(CFBranchLabelScheme, CFBranchLabelSchemeKind, 2, CFBranchLabelSchemeKind::Default,
              "Control-Flow Branch Protection Label Scheme")
+LANGOPT(CFProtectionReturn, 1, 0, "Control-Flow Return Protection enabled")
 LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
 ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
 LANGOPT(IncludeDefaultHeader, 1, 0, "Include default header file for OpenCL")
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index b4aa3206fcfab..dff990d15dd62 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -238,6 +238,9 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
     else
       Builder.defineMacro("__riscv_32e");
   }
+
+  if (Opts.CFProtectionReturn && ISAInfo->hasExtension("zicfiss"))
+    Builder.defineMacro("__riscv_shadow_stack");
 }
 
 static constexpr int NumRVVBuiltins =
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 014e629c959e2..b9a5c0589ebc4 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -4048,8 +4048,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
 
   if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
     StringRef Name = A->getValue();
-    if (Name == "full" || Name == "branch") {
+    if (Name == "full") {
+      Opts.CFProtectionBranch = 1;
+      Opts.CFProtectionReturn = 1;
+    } else if (Name == "branch") {
       Opts.CFProtectionBranch = 1;
+    } else if (Name == "return") {
+      Opts.CFProtectionReturn = 1;
     }
   }
 
diff --git a/clang/test/Preprocessor/riscv-cf-protection-return.c b/clang/test/Preprocessor/riscv-cf-protection-return.c
new file mode 100644
index 0000000000000..3a93a88fa6839
--- /dev/null
+++ b/clang/test/Preprocessor/riscv-cf-protection-return.c
@@ -0,0 +1,44 @@
+// RUN: %clang --target=riscv32 -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -fcf-protection=return -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -fcf-protection=full -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -march=rv32i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv32 -march=rv32i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=return -E -dM %s \
+// RUN: -o - | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// RUN: %clang --target=riscv32 -march=rv32i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=full -E -dM %s -o - \
+// RUN: | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// RUN: %clang --target=riscv64 -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -fcf-protection=return -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -fcf-protection=full -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -march=rv64i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -E -dM %s -o - | \
+// RUN: FileCheck --check-prefixes=NO-MACRO %s
+
+// RUN: %clang --target=riscv64 -march=rv64i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=return -E -dM %s \
+// RUN: -o - | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// RUN: %clang --target=riscv64 -march=rv64i_zicfiss1p0 \
+// RUN: -menable-experimental-extensions -fcf-protection=full -E -dM %s -o - \
+// RUN: | FileCheck --check-prefixes=SHSTK-MACRO %s
+
+// SHSTK-MACRO: __riscv_shadow_stack 1{{$}}
+// NO-MACRO-NOT: __riscv_shadow_stack

Copy link
Member

@kito-cheng kito-cheng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mylai-mtk mylai-mtk merged commit 2fdb26d into llvm:main Feb 18, 2025
10 of 12 checks passed
@mylai-mtk mylai-mtk deleted the zicfiss-define-macros branch February 18, 2025 09:27
wldfngrs pushed a commit to wldfngrs/llvm-project that referenced this pull request Feb 19, 2025
… stack is enabled (llvm#127592)

The `-fcf-protection=[full|return]` flag enables shadow stack
implementation based on RISC-V Zicfiss extension. This patch adds the
`__riscv_shadow_stack` predefined macro to preprocessing when such a
shadow stack implementation is enabled.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants