我比较了 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:
- Classify the return type with the classification algorithm.
- 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/