c++ GNU内联asm:哪些寄存器被__stdcall重写?

wqsoz72f  于 2023-03-09  发布在  其他
关注(0)|答案(1)|浏览(121)

如果我使用call指令,通过C++代码中的GNU内联汇编器,调用一个我知道使用__stdcall约定的函数,我是否必须列出任何被重写的寄存器?
我在互联网上没有找到很好的指导,但是看起来%eax%edx%ecx是调用者保存的,前两个是为返回值保留的。
这是我的代码。我想知道我需要在第三个冒号后面放什么。

#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是我能在网上找到的最好的,但我还没能找到任何说“这是__stdcall假设它可以修改而不保存的东西”的东西...

c0vxltue

c0vxltue1#

MS确实解释了EAX、EDX和ECX会被调用“破坏”,所有其他寄存器必须由被调用方在32位代码link to MSDN docs中保留-使用哪种调用约定无关紧要。
因此,为了清楚起见,需要将ecx标记为crobbered,因为eaxedx已经在内联汇编程序中使用。
对于x86-64,这里有文档,其中指出
寄存器RBX、RBP、RDI、RSI、R12、R13、R14和R15被认为是非易失性的,必须由使用它们的函数保存和恢复。

相关问题