x86-64 System V ABI(用于除Windows之外的所有内容)过去常常访问http://x86-64.org/documentation/abi.pdf,但该网站现已脱离互联网.
该文件是否有新的权威主页?
我试图了解System V AMD64-ABI对于从函数按值返回的含义。
对于以下数据类型
struct Vec3{
double x, y, z;
};
Run Code Online (Sandbox Code Playgroud)
该类型Vec3属于MEMORY类,因此ABI就“返回值”指定了以下内容:
如果类型具有MEMORY类,则调用方将为返回值提供空间,并以%rdi形式传递此存储的地址,就好像它是该函数的第一个参数一样。实际上,此地址成为“隐藏”的第一个参数。该存储不得与通过此参数以外的其他名称对被调用方可见的任何数据重叠。
返回时,%rax将包含调用者在%rdi中传递的地址。
考虑到这一点,以下(傻)功能:
struct Vec3 create(void);
struct Vec3 use(){
return create();
}
Run Code Online (Sandbox Code Playgroud)
可以编译为:
use_v2:
jmp create
Run Code Online (Sandbox Code Playgroud)
我认为,正如ABI所保证的,可以执行尾调用优化,这create会将%rdi传递的值放入%rax寄存器中。
但是,似乎没有一个编译器(gcc,clang和icc)正在执行此优化(此处为godbolt)。生成的汇编代码%rdi仅能将其值移动到%rax,因此保存在堆栈上,例如gcc:
use:
pushq %r12
movq %rdi, %r12
call create
movq %r12, %rax
popq %r12
ret
Run Code Online (Sandbox Code Playgroud)
无论是对于这种最小的,愚蠢的功能,还是对于现实生活中更复杂的功能,都不会执行尾调用优化。这使我相信,我必须丢失某些东西,这是禁止的。
毋庸置疑,对于SSE类的类型(例如,仅2而不是3的两倍),将执行尾调用优化(至少由gcc和clang进行,仅靠戈德螺栓)
use_v2:
jmp create
Run Code Online (Sandbox Code Playgroud)
结果是
use:
jmp create
Run Code Online (Sandbox Code Playgroud) 在谈到C函数的返回值时,返回值存储在EAX寄存器中.假设我们正在谈论32位寄存器,整数欢迎,但是当我们返回这些类型会发生什么:
long long,long double,一struct/ union比32位大.