【问题标题】:GNU inline asm: which registers get clobbered by __stdcall?GNU 内联汇编:__stdcall 破坏了哪些寄存器?
【发布时间】:2013-07-29 19:19:50
【问题描述】:

如果我在 C++ 代码中通过 GNU 的内联汇编器使用 call 指令来调用我知道使用 __stdcall 约定的函数,我是否必须将任何寄存器列为被破坏的?

我在 Internet 上找不到很好的指导,但看起来 %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 假设它可以在不保存的情况下修改的内容”...

【问题讨论】:

  • 每个平台都有不同的限制(例如,Windows 和 Linux 的要求不同,更不用说 32 位和 64 位)。我找到的最好的资源是Agner Fog's C++ calling conventions,它将为您提供所需的信息以及更多信息。
  • 谢谢。 @Mats,无论出于何种原因,Wiki 中的“指定用于函数内”对我来说都不够明确,但这一定是他们所说的。
  • @syam,那本手册很棒。看起来第 6 章总结了它。
  • 正如我在下面的答案中所记录的,MS 对此有相当不错的文档。

标签: c++ gcc x86 inline-assembly stdcall


【解决方案1】:

MS 确实解释了 EAX、EDX 和 ECX 被调用“破坏”,所有其他寄存器必须由被调用者以 32 位代码保存,link to MSDN docs - 使用哪种调用约定都没有关系。

所以,为了清楚起见,您需要将 ecx 标记为已破坏,因为您的内联汇编器中已经使用了 eaxedx

对于 x86-64,文档是 here,并说

寄存器 RBX、RBP、RDI、RSI、R12、R13、R14 和 R15 被认为是非易失性的,必须由使用它们的函数保存和恢复。

【讨论】:

    猜你喜欢
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-09
    相关资源
    最近更新 更多