如果我使用
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
这个消息线程是我在互联网上能找到的最好的,但我找不到任何说“这就是
__stdcall
假设它可以在不保存的情况下修改”的东西...
MS 确实解释了 EAX、EDX 和 ECX 被调用“破坏”,所有其他寄存器必须由被调用者以 32 位代码保存,链接到 MSDN 文档——使用哪种调用约定并不重要。
所以,为了清楚起见,您需要将
ecx
标记为已损坏,因为 eax
和 edx
已经在内联汇编器中使用了。
对于 x86-64,文档在这里,并说
寄存器 RBX、RBP、RDI、RSI、R12、R13、R14 和 R15 被认为是非易失性的,必须由使用它们的函数保存和恢复。