llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.24k stars 11.66k forks source link

__builtin_frame_address(0) returning RSP for x86_64-windows (instead of RBP) #51055

Open 2e1c2d01-a631-41c2-93fe-8d40b95d8607 opened 3 years ago

2e1c2d01-a631-41c2-93fe-8d40b95d8607 commented 3 years ago
Bugzilla Link 51713
Version trunk
OS Linux
Attachments Repro
CC @topperc,@RKSimon,@phoebewang,@rnk,@rotateright

Extended Description

$ cat frameaddr.c

void bar(int *n);

void foo(int *p, int n) { asm volatile ("nop"); p = builtin_frame_address(0); asm volatile__ ("nop"); bar(&n); }

$ clang --target=x86_64-windows frameaddr.c -c -o - | llvm-objdump -d -

: file format coff-x86-64 Disassembly of section .text: 0000000000000000 : 0: 55 pushq %rbp 1: 48 83 ec 30 subq $48, %rsp 5: 48 8d 6c 24 30 leaq 48(%rsp), %rbp a: 89 55 fc movl %edx, -4(%rbp) d: 48 89 4d f0 movq %rcx, -16(%rbp) 11: 90 nop 12: 48 8d 4d d0 leaq -48(%rbp), %rcx 16: 48 8b 45 f0 movq -16(%rbp), %rax 1a: 48 89 08 movq %rcx, (%rax) 1d: 90 nop 1e: 48 8d 4d fc leaq -4(%rbp), %rcx 22: e8 00 00 00 00 callq 0x27 27: 90 nop 28: 48 83 c4 30 addq $48, %rsp 2c: 5d popq %rbp 2d: c3 retq The instruction "leaq -48(%rbp), %rcx" at 0x12 should instead be something like "movq %rbp, %rcx". I don't know whether this is expected, but this behavior breaks __builtin_longjmp for x86_64-windows (#50142 ).
rnk commented 3 years ago

builtin_frame_address effective returns the address-of the return address, not the contents of RBP, since those are effectively not useful to most callers of builtin_frame_address.

Hang on, that's not what I'm observing. There's something going on that I don't understand. As you say, it is returning the established SP value after the prologue, which seems inconsistent with the code I linked to.

rnk commented 3 years ago

This was intentional: https://github.com/llvm/llvm-project/commit/13d0b11d7b4e22da01dcef85e5302296edd8aa9e

builtin_frame_address effective returns the address-of the return address, not the contents of RBP, since those are effectively not useful to most callers of builtin_frame_address.

If you increase the stack memory used by foo in your example, you will see how RBP and the frame address begin to diverge.

I'm unaware of anyone successfully using __builtin_setjmp/longjmp on Windows. We have taken steps to make regular MSVC setjmp/longjmp work well.