Question

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"...

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top