什么真的是什么意思?

时间:2016-11-17 18:44:51

标签: c llvm abi

我比较了返回结构的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寄存器。为什么呢?

1 个答案:

答案 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文件

确认
  

返回值值的返回根据以下内容完成   算法:

     
      
  1. 使用分类算法对返回类型进行分类。
  2.   
  3. 如果类型有类MEMORY (ndMarco:即大东西),那么调用者会为返回提供空间   value并将该存储的地址传递给%rdi,就像它是第一个一样   函数的参数。实际上,该地址成为“隐藏的”第一个参数。   此存储不得与被叫方可见的任何数据重叠   除此论点之外的其他名称。   返回时,%rax将包含已传入的地址   调用者在%rdi。
  4.