]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V] Correct CFA notes for stack-clash protection [PR120714]
authorAlexey Merzlyakov <alexey.merzlyakov@samsung.com>
Mon, 30 Jun 2025 19:58:29 +0000 (13:58 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Mon, 30 Jun 2025 19:58:29 +0000 (13:58 -0600)
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.

gcc/config/riscv/riscv.cc
gcc/testsuite/gcc.target/riscv/pr120714.c [new file with mode: 0644]

index f5d2b2e74aede28f03c54a325c5793370a01d387..cd6d6b992b5068dbf28767d75bf8cb9420850bb7 100644 (file)
@@ -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 (file)
index 0000000..dd71a3e
--- /dev/null
@@ -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;
+}