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.

Reply via email to