x86-64 调用约定中的返回值


  1. 如果我编写一个返回 void 的函数,根据 x86-64 约定调用,我可以破坏 rax/eax 吗?
  2. 关于返回双精度的函数的类似问题(因为实际返回将发生在 xmm0 中)
  3. 如果我做 movq xmm0 -> rax。然后我得到一个可以放入的数字

    union { 
    int, 
    double
    };
    

    通过 int。然后当我通读双倍时,我得到了预期的双倍。我的行为有哪些陷阱?

rax是一个暂存寄存器,double在类 SSE 中,因此它以xmm0/xmm1返回。这些都记录在 SysV ABI 中。没有什么可以阻止您在将返回值放置之前将xmm0用作临时。在 x86 标签 wiki 中有指向 ABI 文档的链接。

要回答#3,我们需要查看您的代码。也许是 UB 在C++,或者您的程序集是错误的。

  1. 是的,void函数可以在所有arg返回寄存器(RAX,RDX,XMM0等)中保留任何它们想要的内容。void意味着调用方不应该对你留在任何地方的任何值做任何事情(当然,除了调用保留的寄存器,如RBX、RBP和RSP)。

  2. 类似于什么? 函数不能声明为返回void double,所以IDK你在问什么。

  3. MOVQ 允许您复制double的二进制表示形式。 是的,当然,您可以将该 64 位整数键入双关语,并在 C99 中输入并集的double。 但在C++,联合类型双关只作为GNU扩展是合法的。 在asm中,它只是您可以随心所欲地复制的位。

请注意,具有int成员的联合是伪造的,因为这在 x86-64 SysV ABI 中只有 32 位。 您可能正在截断尾数的低 32 位,因此您可能只对尾数的低位都为零的小整数进行了测试。

实际上,这听起来不对;它应该截断double的高半部分,因为x86的浮点字节顺序在最高地址存储包含符号位的字节。因此,除非您使用 asm 中的 64 位存储存储在联合中,否则它应该不起作用。

最新更新