https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120714
Bug ID: 120714 Summary: RISC-V: incorrect frame pointer CFA address for stack-clash protection loops Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: alexey.merzlyakov at samsung dot com Target Milestone: --- Created attachment 61666 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61666&action=edit repro-testcase for running with GDB The following test-case, when compiling for rv64gc with -O1 -g2 -fstack-clash-protection produces incorrect DWARF information: #include <stdio.h> #define MAX 4000 void goo () { printf("goo()\n"); } 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 () { printf("ret = %i\n", foo(20)); return 0; } When running produced binary under GDB or backtracing with libunwind, it can't get the right frame after foo(): ~$ gdb stack7.sc.x ... (gdb) b goo Breakpoint 1 at 0x10584: file stack7.c, line 6. (gdb) r ... (gdb) bt #0 goo () at stack7.c:6 #1 0x00000000000105da in foo (a=<optimized out>) at stack7.c:16 #2 0x0000000000000f9f in ?? () <- should be main() This appears due to incorrect .cfi_def_cfa_offset stack pointer addresses after stack-clash checking loop: foo: addi sp,sp,-16 .cfi_def_cfa_offset 16 sd ra,8(sp) sd s0,0(sp) li t1,28672 sub t1,sp,t1 .cfi_def_cfa 5, 28672 .cfi_offset 1, -8 .cfi_offset 8, -16 li t0,4096 .L6: sub sp,sp,t0 sd zero,1024(sp) bne sp,t1,.L6 .cfi_def_cfa_register 2 li t0,4096 addi t0,t0,-768 sub sp,sp,t0 .cfi_def_cfa_offset 32000 <- wrong value SP at this point is shifted on 32016 value instead of 32000, which confirms by assembler made w/o stack-clash protection option: foo: addi sp,sp,-16 .cfi_def_cfa_offset 16 sd ra,8(sp) sd s0,0(sp) li t0,-32768 addi t0,t0,768 add sp,sp,t0 .cfi_def_cfa_offset 32016 <- correct Uncounted difference in 16 bytes is seem to have in riscv_allocate_and_probe_stack_space() function. It uses the "remaining_size" as basis for calculation the stack shift value, when adding reg note with REG_CFA_DEF_CFA. However, the remaining_size represents stack frame size that might be previously reduced in riscv_expand_prologue(). Real stack pointer shift value might be corrected with "cfa_offset = frame.total_size - remaining_size" value when adding REG_CFA_DEF_CFA notes for stack clash prologue handling in riscv_allocate_and_probe_stack_space().