https://gcc.gnu.org/g:45a17e3081120f51f8e8b1d7cda73c7d89453e85

commit r16-1834-g45a17e3081120f51f8e8b1d7cda73c7d89453e85
Author: Alexey Merzlyakov <alexey.merzlya...@samsung.com>
Date:   Mon Jun 30 13:58:29 2025 -0600

    [RISC-V] Correct CFA notes for stack-clash protection [PR120714]
    
    Fixes incorrect SP-addresses used in CFA notes for the stack probes
    unrelative to the frame's top. It applied to the RISC-V targets code
    generation when the stack-clash protection is enabled.
    
            PR target/120714
    gcc/ChangeLog:
    
            * config/riscv/riscv.cc (riscv_allocate_and_probe_stack_space):
            Fix SP-addresses in REG_CFA_DEF_CFA notes for stack-clash case.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/pr120714.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                 | 13 ++++++++--
 gcc/testsuite/gcc.target/riscv/pr120714.c | 40 +++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index f5d2b2e74aed..cd6d6b992b50 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -8978,12 +8978,20 @@ riscv_allocate_and_probe_stack_space (rtx temp1, 
HOST_WIDE_INT size)
       temp2 = riscv_force_temporary (temp2, gen_int_mode (rounded_size, 
Pmode));
       insn = emit_insn (gen_sub3_insn (temp2, stack_pointer_rtx, temp2));
 
+      /* The size does not represent actual stack pointer address shift
+        from the top of the frame, as it might be lowered before.
+        To consider the correct SP addresses for the CFA notes, it is needed
+        to correct them with the initial offset value.  */
+      HOST_WIDE_INT initial_cfa_offset
+       = cfun->machine->frame.total_size.to_constant () - size;
+
       if (!frame_pointer_needed)
        {
          /* We want the CFA independent of the stack pointer for the
             duration of the loop.  */
          add_reg_note (insn, REG_CFA_DEF_CFA,
-                       plus_constant (Pmode, temp1, rounded_size));
+                       plus_constant (Pmode, temp1,
+                                      initial_cfa_offset + rounded_size));
          RTX_FRAME_RELATED_P (insn) = 1;
        }
 
@@ -8996,7 +9004,8 @@ riscv_allocate_and_probe_stack_space (rtx temp1, 
HOST_WIDE_INT size)
        {
          insn = get_last_insn ();
          add_reg_note (insn, REG_CFA_DEF_CFA,
-                       plus_constant (Pmode, stack_pointer_rtx, rounded_size));
+                       plus_constant (Pmode, stack_pointer_rtx,
+                                      initial_cfa_offset + rounded_size));
          RTX_FRAME_RELATED_P (insn) = 1;
        }
 
diff --git a/gcc/testsuite/gcc.target/riscv/pr120714.c 
b/gcc/testsuite/gcc.target/riscv/pr120714.c
new file mode 100644
index 000000000000..dd71a3e11d3d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr120714.c
@@ -0,0 +1,40 @@
+/* Test checking that the backtrace on large frame size with additional
+   SP shift in the prologue won't broken when compiled with the
+   -fstack-clash-protection option.  */
+/* { dg-do run { target { *-*-linux* } } } */
+/* -O0 does not have enough optimizations.
+   -O2/-O3 does inline and reduces number of addresses in the backtrace.  */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O2" "-O3" } } */
+/* { dg-options "-g -fstack-clash-protection" } */
+
+#include <execinfo.h>
+
+#define MAX 4000
+
+void goo ()
+{
+  int addresses;
+  void *buffer[10];
+
+  addresses = backtrace (buffer, 10);
+  if (addresses != 6)
+    __builtin_abort ();
+}
+
+int foo (int a)
+{
+  long long A[MAX];
+  for (int i = 0; i < MAX; i++)
+    A[i] = i;
+
+  goo ();
+
+  return A[a % MAX];
+}
+
+int main ()
+{
+  if (foo (20) != 20)
+    __builtin_abort ();
+  return 0;
+}

Reply via email to