https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128270

--- Comment #2 from Uroš Bizjak <ubizjak at gmail dot com> ---
The missing .cfi_restore 6 is caused by the red-zone early return in
ix86_add_cfa_restore_note, not by dwarf2cfi or ix86_emit_leave.

With DRAP, the prologue saves the caller’s %rbp with a DW_CFA_expression rule
(breg6 (rbp) + 0, the .cfi_escape 0x10,0x6,0x2,0x76,0), so the rule is
evaluated through %rbp itself. After leave (or popq %rbp), %rbp holds the
caller’s value, and the stale rule then reads from the wrong address. gdb shows
a truncated backtrace if you stop right after leave.

ix86_add_cfa_restore_note skips the note when cfa_offset <= red_zone_offset, on
the assumption that “unwinders can find the same value in the register and on
the stack”. That holds for a DW_CFA_offset rule but not for the DRAP expression
rule.

Evidence:

* At -DALIGN=32, insn 28 in .pro_and_epilogue is a plain insn with (nil) notes.
At -DALIGN=128 it is insn/f with REG_CFA_RESTORE (reg/f:DI 6 bp). The save slot
is outside the red zone in the larger frame, which is why larger alignments
appeared to fix it.
* -mno-red-zone at -DALIGN=32 emits .cfi_restore 6 after leave.
* -mtune-ctrl=^use_leave at -DALIGN=32 emits popq %rbp with no restore. The
same helper is used by ix86_emit_restore_reg_using_pop.

Reply via email to