https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128611
Bug ID: 128611
Summary: __builtin_dwarf_cfa returns wrong address in a
DRAP-realigned frame
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: ishevlyakov at gcc dot gnu.org
Target Milestone: ---
Host: x86_64-pc-linux-gnu, i686-pc-linux-gnu
In a function whose frame is realigned through a DRAP (dynamic realign
argument pointer), __builtin_dwarf_cfa () does not return the CFA.
Testcase:
extern void abort (void);
__attribute__ ((noipa)) void
sink (volatile char *p)
{
p[0] = 0;
}
__attribute__ ((noipa)) void *
plain (void)
{
return __builtin_dwarf_cfa ();
}
__attribute__ ((noipa)) void *
realigned (void)
{
volatile char buf[64] __attribute__ ((aligned (64)));
sink (buf);
return __builtin_dwarf_cfa ();
}
int
main (void)
{
if (plain () != realigned ())
abort ();
return 0;
}
Both functions are called from the same frame in main, so they must see
the same CFA.
$ gcc -O2 -mforce-drap t.c && ./a.out # x86_64: aborts
$ gcc -m32 -O2 t.c && ./a.out # i686: aborts, no extra flag
# needed (DRAP is used anyway)
$ gcc -O2 t.c && ./a.out # x86_64 without DRAP: passes
Fails at -O0 through -O3 and -Os; -mstackrealign does not matter.
Printing the two values (x86_64, -O2 -mforce-drap):
plain=0x7ffe43872680 realigned=0x7ffe43872640
x86_64 -O2 -mforce-drap code for realigned():
leaq 8(%rsp), %r10 # r10 = CFA (DRAP)
andq $-64, %rsp
pushq -8(%r10) # copy of return address
pushq %rbp
movq %rsp, %rbp
pushq %r10
...
leaq 16(%rbp), %rax # "CFA" = argp eliminated via hard fp
leave
The CFA should be %r10 (the DRAP). What is returned instead is %rbp+16,
the address just above the copy of the return address pushed after
realignment, i.e. an address inside the realigned frame.