https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128270
Bug ID: 128270
Summary: x86-64: gcc sometimes generates wrong CFI for DRAP
function epilogues
Product: gcc
Version: 16.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: alkondratenko at gmail dot com
Target Milestone: ---
Here is test case (modeled after aw-backtrace's amd64-drap-test.c)
---
void use(void *);
#ifndef ALIGN
#define ALIGN 32
#endif
int f(void)
{
char buf[64] __attribute__((aligned(ALIGN)));
use(buf);
return buf[0];
}
---
$ gcc -O2 -mforce-drap -S drap.c
produces this (comments are mine):
---
.file "drap.c"
.text
.p2align 4
.globl f
.type f, @function
f:
.LFB0:
.cfi_startproc
leaq 8(%rsp), %r10 # r10 holds RSP of the caller, so is CFA
.cfi_def_cfa 10, 0
andq $-32, %rsp # this realigns the stack
pushq -8(%r10) # caller's address is pushed for the "fake"
frame-pointer frame
pushq %rbp
movq %rsp, %rbp # callers rbp is saved and new rbp is realigned
stack frame pointer
.cfi_escape 0x10,0x6,0x2,0x76,0 # DW_CFA_expression: r6 (rbp)
(DW_OP_breg6 (rbp): 0); i.e. caller's RBP is stored at this frame's RBP
pushq %r10
.cfi_escape 0xf,0x3,0x76,0x78,0x6 # DW_CFA_def_cfa_expression
(DW_OP_breg6 (rbp): -8; DW_OP_deref); i.e. CFA is now defined as address stored
at this frame's RBP minus 8. What we just pushed above
leaq -80(%rbp), %rdi
subq $72, %rsp
call use@PLT
movq -8(%rbp), %r10
.cfi_def_cfa 10, 0 # epilogue started and we're back to use r10 as CFA
movsbl -80(%rbp), %eax
leave # this restores rbp to be caller's rbp; *but* the CFI for RBP
still says "stored at address in RBP"
#.cfi_restore 6 is missing here
leaq -8(%r10), %rsp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size f, .-f
.ident "GCC: (Debian 16.2.0-4) 16.2.0"
.section .note.GNU-stack,"",@progbits
---
For some reason using ALIGN larger than 64 "fixes" the problem. This happens at
least in gcc-15 and gcc-16 and likely other versions.
Lack of CFI restore at epilogue will occasionally crash unwinders other than
aw-backtrace due to incorrect unwind rule for RBP. And you can see it in gdb
too by stopping just after leave and invoking 'bt' command and you'll get
truncated backtrace.