how C compiler treats a struct return value from a function, in ASM

assembly, c, calling-convention, return, x86

Solution

In common x86 calling conventions, objects that fit in two registers are returned in `RDX:RAX`. This is the same register pair that is an implicit input/output for div and mul instructions, and for `cdq` / `cqo` (sign extend e/rax into e/rdx).

The i386 Linux (SysV) calling convention only returns 64bit integers that way. Structs (even a struct consisting of a single `int32_t`) use the hidden-parameter method instead of being packed `eax` or `edx:eax`. 64bit Linux, and Microsoft's current standard `__vectorcall`, both pack structs into `e/rax`, or `e/rdx:e/rax`.

Many calling conventions handle larger objects by adding a hidden extra parameter: a pointer to space for storing the return value. Consult the ABI documentation for the specific ABI you are using. (links at in the x86 wiki).

Compared to other calling conventions discussed in comments (e.g. implicitly using space on the stack to store large objects being returned), passing a pointer can save a copy, because the pointer can point to the final destination instead of scratch space on the stack.

But usually only if the final destination is on the stack. The callee can assume the return-value object is not the same object as / doesn't alias any global or any memory it can reach via pointers. i.e. the caller has to do escape analysis. See What prevents the usage of a function argument as hidden pointer? - In the C abstract machine, the return value object isn't written until the moment the function is returning, after it's done reading anything.

But it can point to whatever convenient place in the caller's stack frame, not a fixed place relative to RSP, which may avoid a copy.

Problem

When speaking about C function's return value, the return value is stored in the `EAX` register. Suppose we are speaking about 32 bit register, integers are welcomed, but what happens when we return these types: `long long`, `long double`, a `struct`/`union` that is larger than 32bit.

Original source

Related problems