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

时间:2016-11-22 12:05:24

标签: c++ linux assembly x86-64 abi

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

    的号码
    union { 
        int, 
        double
    };
    

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

2 个答案:

答案 0 :(得分:2)

rax是一个临时注册,double位于SSE类中,因此会在xmm0 / xmm1中返回。这些记录在SysV ABI中。在将返回值放入之前,没有什么可以阻止您使用xmm0作为临时。 x86 tag wiki中有ABI文档的链接。

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

答案 1 :(得分:0)

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

  2. 类似于什么?一个函数不能被声明为返回void double,所以IDK就是你所要求的。

  3. MOVQ允许您复制double的二进制表示。是的,当然你可以使用C99中的union将64位整数输回到double。但是在C ++中,union type-punning只作为GNU扩展而合法。在asm中,它只是你可以随意复制的所有内容。

  4. 请注意,与int成员的联合是伪造的,因为x86-64 SysV ABI中只有32位。你可能会截断你的尾数的低32位,所以你可能只测试了尾数的低位全为零的小整数。

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