What does it really mean?

I compared two C functions returning a structure. We know that at the ABI level, large structures will follow the pointer as the first argument to the function.

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; } 

For these functions, I checked the build for x86_64 Linux and Windows. fsret declared as void @fsret(%struct.S* sret %s) .

Comparing these two options, there is no difference on the side of the called party. However, inside functions, fsret additionally copies its first argument (a pointer to a structure) into the RAX register. Why?

+6
source share
1 answer

The reason is this review diff:

 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. 

so that the caller must fill in the memory provided by the caller and return the pointer that was also transmitted.

This is confirmed by x86_64 document r252 System V ABI

Return values ​​Return values ​​are performed in accordance with the following Algorithm:

  • Classify the return type using the classification algorithm.
  • If the type has the MEMORY class (ndMarco: i.e. large material), then the caller provides a place to return the value and passes the address of this store to% rdi, as if it were the first argument to the function. Essentially, this address becomes the "hidden" first argument. This store should not overlap any data visible to the called other names than this argument. Upon return,% rax will contain the address that the caller in% rdi sent.
+4
source

Source: https://habr.com/ru/post/1012424/


All Articles