If I am using the call
instruction, via GNU's inline assembler in C++ code, to call a function I know uses the __stdcall
convention, do I have to list any registers as clobbered?
I'm not finding great guidance on the internet, but it looks like %eax
, %edx
, and %ecx
are caller-save, with the former two being reserved for the return value.
Here's my code. I want to know what I need to put after the third colon.
#include <cstdint>
namespace {
inline uint64_t invoke_stdcall(uint64_t (* stdcall_func)())
{
unsigned long hi32, lo32;
asm(
"call %2"
: "=d" (hi32), "=a" (lo32)
: "m" (stdcall_func)
: /* HELP! What goes here? */
);
return static_cast<uint64_t>(hi32) << 32 | static_cast<uint32_t>(lo32);
}
} // anonymous namespace
This message thread is the best I can find on the internet, but I haven't been able to find anything that says "this is what __stdcall
assumes it can modify without saving"...
MS does explain that EAX, EDX and ECX are "destroyed" by calls, all other registers must be preserved by callee in 32-bit code, link to MSDN docs - it doesn't matter which calling convention is used.
So, to be clear, you need to mark ecx
as clobbered, since eax
and edx
are already being used in your inline assembler.
And for x86-64, the documentation is here, and says
The registers RBX, RBP, RDI, RSI, R12, R13, R14, and R15 are considered nonvolatile and must be saved and restored by a function that uses them.