问题
(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??
回答1:
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.
回答2:
perhaps rax is big enough to hold the entire structure. At 0x00000000004004c7 you're getting the entire structure (with mov), not its address (you'd use lea instead)
回答3:
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.
回答4:
Your original code is returning a copy of the structure created in the function - because you're returning a structure type, not a pointer to a structure. What it looks like is that the entire structure is passed by value with rax. Generally speaking, the compiler can produce various assembly codes for this, depending and caller and callee behavior and calling convention.
The proper way to handle structure is to use them as out parameters:
void func(t_test* t)
{
t->i = 100;
t->c = 'a';
}
回答5:
The stack pointer isn't changed in the start of the function, so the allocation of t_test isn't made within the function, and thus not freed by the function. How this is handled depends on the calling convention used. If you look at how the function is called it can be easier to see how it is done.
来源:https://stackoverflow.com/questions/6731140/how-does-c-return-a-structure