c - sret 到底是什么意思?

标签 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 寄存器。为什么?

最佳答案

原因在于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 文档

Returning of Values The returning of values is done according to the following algorithm:

  1. Classify the return type with the classification algorithm.
  2. If the type has class MEMORY (ndMarco: i.e. big stuff), then the caller provides space for the return value and passes the address of this storage in %rdi as if it were the first argument to the function. In effect, this address becomes a “hidden” first argument. This storage must not overlap any data visible to the callee through other names than this argument. On return %rax will contain the address that has been passed in by the caller in %rdi.

关于c - sret 到底是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40662704/

相关文章:

c++ - GCC API 无法分解其自己的导出符号

c++ - 避免 unix 中的标准库冲突

c 链表,offsetof 返回值不允许强制转换回父结构地址

c - 如果使用用户定义函数和 main() 函数访问全局声明的数组元素,为什么会得到不同的值?

linux - 从源代码安装后如何卸载 libc++?

linker - LLVM 使用外部函数

c++ - 是否可以使用不同 ABI 的外部库构建应用程序

c - 后台进程写入 STDOUT 时没有 SIGTTOU

c - fork 重复两次?

compiler-construction - LLVM中的部分应用