How does C return a structure? [duplicate]

(gdb) disas func
Dump of assembler code for function func:
0x00000000004004b8 <func+0>:    push   %rbp
0x00000000004004b9 <func+1>:    mov    %rsp,%rbp
0x00000000004004bc <func+4>:    movl   $0x64,0xfffffffffffffff0(%rbp)
0x00000000004004c3 <func+11>:   movb   $0x61,0xfffffffffffffff4(%rbp)
0x00000000004004c7 <func+15>:   mov    0xfffffffffffffff0(%rbp),%rax
0x00000000004004cb <func+19>:   leaveq
0x00000000004004cc <func+20>:   retq
End of assembler dump.


t_test func()
{
    t_test t;
    t.i = 100;
    t.c = 'a';
    return t;
}

So it seems it's returning the local variable t,but is this kind of job guaranteed to work, isn't it supposed not to refer to any local variables when return??


In my experience, there is no standard way how C returns a structure. To be able to pass a struct, the compiler usually (invisibly to the user) passes a pointer to the struct, to which the function can copy the contents. How this pointer is passed (first or last on stack) is implementation dependent. Some compilers, like 32 bit MSVC++ return small structures in registers like EAX and EDX. Apparently, GCC returns such a struct in RAX, in 64 bit mode.

But, once again, there is no standard way how this is done. That is no problem when the rest of the code using a function is also compiled by the same compiler, but it is a problem if the function is an exported function of a DLL or a lib. I have been bitten by this a few times, when using such functions from a different language (Delphi) or from C with a different compiler. See this link too.


RAX is big enough to hold the entire structure. At 0x00000000004004c7 you're loading the entire structure (with mov), not its address (you'd use lea instead).

The x86-64 System V ABI's calling convention returns C structs up to 16 bytes in RDX:RAX or RAX. C++ on x86-64: when are structs/classes passed and returned in registers?

For larger structs, the there's a "hidden" output pointer arg passed by the caller.


It's not really standard at all how things are returned, but it's usually in RAX. In your example, assuming t_test::i and t_test::c are the only members of t_test and are at most 32-bits each, the entire structure can fit into a 64-bit register, so it just returns the values directly through RAX, and usually things that can fit into 2 registers are returned in RAX:RDX (or RDX:RAX, I forget the common order).

For larger than two registers, it generally involves a hidden pointer parameter being passed as the first parameter, which points to an object in the calling function (usually the one that directly gets assigned the return value). This object is then written to before returning from the called function (usually copied from the local structure used in the called function), and usually the same pointer that was passed is returned in RAX.

EAX/EDX can be substituted in for RAX/RDX on 32-bit x86 systems.

With conventions that pass the "this" pointer on the stack (like standard x86 GCC conventions), the return value pointer is usually passed as a hidden second parameter, instead of the first.