Broken frame chain prolog on x86_64

When I compile code with Clang, I get function prologue without (RBP, RIP) pairs so stack tracing is not working. Is it possible to force producing function prologue with (RBP, RIP) pairs? I need it for low-level debugging. No external debuggers and table based stack unwinders are available.

000000018008fd30 <call_window_proc>:
   18008fd30:	55                   	push   rbp
   18008fd31:	41 56                	push   r14
   18008fd33:	56                   	push   rsi
   18008fd34:	57                   	push   rdi
   18008fd35:	53                   	push   rbx
   18008fd36:	48 83 ec 20          	sub    rsp,0x20
   18008fd3a:	48 8d 6c 24 20       	lea    rbp,[rsp+0x20]

Compiled with clang -target x86_64_windows -fno-omit-frame-pointer -O2.

That example has a normal full prologue? RIP is pushed by the caller’s CALL instruction, RBP is pushed there and RBP is updated to point at the top of the frame. I don’t get what you think is missing.

New RBP value don’t point to previous (RBP, RIP) pair. It should be lea rbp,[rsp+0x40] instead of lea rbp,[rsp+0x20].

Sorry, frame pointer unwinding doesn’t work on x64 Windows. So far as I know, it is impossible to produce SEH unwind info that is correct at every instruction pointer, while also supporting traditional RBP based unwinding. At least, this is what we concluded when we made these design decisions back in 2014. The .seh_setframe directive must come last, after all of the CSRs are pushed, and I believe it has an implementation limit on the displacement, so if your stack frame is more than 256 bytes or so, it is impossible to describe the displacement. I don’t have easy access to my Windows machine right now, so I may be wrong about some details, but in any case, I can confirm that this was the reasoning behind these decisons.

2 Likes