Open
Description
The rbp
register can be clobbered by inline assembly, like so:
void simplenop(void) {
asm volatile("nop" : : : "rbp");
}
This results in the following expected assembly:
simplenop(): # @simplenop()
push rbp
nop
pop rbp
ret
However, when a frame pointer is forced, this clobber constraint is not respected:
void buffernop(int size) {
char buf[size];
asm volatile("nop" : : "r"(buf): "rbp");
}
buffernop(int): # @buffernop(int)
push rbp
mov rbp, rsp
mov eax, edi
mov rcx, rsp
add rax, 15
and rax, -16
sub rcx, rax
mov rsp, rcx
nop
mov rsp, rbp
pop rbp
ret
As you can see, the generated code clearly expects the rbp
to not be clobbered after the inline assembly.
Godbolt link: https://godbolt.org/z/osMEb1Kcj
This resulted in an actual bug in tinygo-org/tinygo#3103 (comment) where I try to call functions with a custom ABI via inline assembly.
Ideally the X86 backend should save the rbp
register somewhere else (for example, on the stack: rsp
is not clobbered) or just throw an error. Silently miscompiling results in bugs.