Consider the following simplified example function:
void foo(void) {
int t;
asm("push %0\n\t"
"push %0\n\t"
"call bar"
:
: "m" (t)
:
);
}
If I compile it with Cygwin x86 gcc 4.8.3 without optimization, the push instructions become:
push -4(%ebp)
push -4(%ebp)
This is good. The problem happens with -O:
push 12(%esp)
push 12(%esp)
This is clearly wrong. The first push changes esp, and the second push then accesses the wrong location. I have read that adding "%esp" to the clobber list should fix it, but it does not help. How can I make GCC use a frame pointer or properly consider esp changes?
(Assume that returning from the bar function will set esp to the value it had before the asm statement. I just need to call a thiscall function and am using inline assembly for that.)
"r" (&t)
? That gives mepush %rax\npush %rax
. – David Wohlferd%ebp
or%esp
as constraints IIRC, nor%ebx
on an ELF (PIC) platform. I think @DavidWohlferd should submit an answer - it's a good choice, since%eax
is often clobbered as a return value anyway. But"a" (&t)
instead. – Brett Hale%eax
is getting returned, then we should probably do something more like"=a" (retval) : "0" (&t)
. After all, we'd have to let gcc know the contents of eax are changing. I will say that calling back into c++ code is going to be tricky. Have you pushed every register the callee might change before doing the call (and popped them on return)? Are you sure everything bar might need that gcc has stored in registers got flushed back to memory before doing the call? It's possible there are no options here, but using inline asm for this would not be my first choice. – David Wohlferd