我比较了返回结构的2个C函数。我们知道在ABI级别上,大型结构将被指针作为第一个函数参数传递。
struct S {
int words[8];
};
struct S fsret() {
struct S s;
s.words[0] = 1;
return s;
}
void fout(struct S* s) {
s->words[0] = 1;
}
对于这些功能,我检查了x86_64 Linux和Windows的程序集。 fsret
被声明为void @fsret(%struct.S* sret %s)
。
比较这两种变体,被叫方没有区别。但是,在函数内部,fsret
还将其第一个参数(指向结构的指针)复制到RAX寄存器。为什么呢?
答案 0 :(得分:4)
原因在于this审查差异:
if (Subtarget->is64Bit() || Subtarget->isTargetKnownWindowsMSVC()) {
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
// The x86-64 ABIs require that for returning structs by value we copy
// the sret argument into %rax/%eax (depending on ABI) for the return.
// Win32 requires us to put the sret argument to %eax as well.
// Save the argument into a virtual register so that we can access it
// from the return points.
所以被调用者必须填充调用者提供的内存和返回它传递的指针。
这由x86_64 r252 System V ABI文件
确认返回值值的返回根据以下内容完成 算法:
- 使用分类算法对返回类型进行分类。
- 如果类型有类MEMORY (ndMarco:即大东西),那么调用者会为返回提供空间 value并将该存储的地址传递给%rdi,就像它是第一个一样 函数的参数。实际上,该地址成为“隐藏的”第一个参数。 此存储不得与被叫方可见的任何数据重叠 除此论点之外的其他名称。 返回时,%rax将包含已传入的地址 调用者在%rdi。
醇>