Hi,
On Wed, 8 Aug 2007, Maurizio Vitale wrote:
> with reference to the following:
>
> struct data {
> data (long v) : m_data (v) {}
> data (const data&) {}
> long m_data;
> };
>
> data foo (data v) {
> return v;
> }
>
> my reading of the x86_64 ABI (v .98, sept 2006) on page 17 is that
> data should have class MEMORY when passed as argument to function foo.
> This because it has a non-trivial copy constructor
> (it is not implicitely declared).
That is correct.
> But GCC 4.1.1 and a more recent version from svn give (for foo):
>
> .globl _Z3foo4data
> .type _Z3foo4data, @function
> _Z3foo4data:
> .LFB8:
> movq %rdi, %rax
> ret
> .LFE8:
That is also correct.
> [so v is passed in a register]
But this conclusion isn't. In short: that's the address of the return
slot.
Longr version:
Your confusion stems from the fact, that your
copy-ctor is empty (so it's code can't be seen in the asm dump), and that
also your return type of 'foo' is data, which also needs to be returned by
memory. Returning in memory is done by the caller allocating the place
for the return value on its stack, and giving the address of that
to-be-written-to place as implicit first argument to the function. That
address is then also returned in %rax.
So what's placed in %rdi here is not 'v' itself, but some place on it's
callers stack, which is also to be returned in %rax. As you have an empty
copy-ctor you also don't see any other interesting access to 'v' itself,
so the asm is confusing because nothing hints at the fact that %rdi really
only holds the address of the return slot. Look at some arbitrary caller
of your foo function. For clarity I've also removed the empty body of of
cctor, so that calls to external functions remain:
data foo (data v) { return v; }
void callfoo()
{
data d(32);
foo (d);
}
callfoo now looks like so:
Z7callfoov:
pushq %rbx
subq $48, %rsp
leaq 16(%rsp), %rbx
leaq 32(%rsp), %rsi
movq $32, 32(%rsp)
movq %rbx, %rdi
call _ZN4dataC1ERKS_
movq %rsp, %rdi
movq %rbx, %rsi
call _Z3foo4data
addq $48, %rsp
popq %rbx
ret
You can see three objects overall allocated on the stack
(%rsp,%rsp+16,%rsp+32). In particular the one at %rsp is used for the
return slot for the call of 'foo'. foo itself is given the address of
that return slot, and it's input argument 'd', placed in memory at %rsp+16
(initialised by the cctor from the object at %rsp+32). So it's passed and
return in memory, as defined by the ABI.
The passing by memory can be seen easier by actually accessing something
in the object, like here:
long access (data v) { return v.m_data; }
That's assembled into
_Z6access4data:
movq (%rdi), %rax
ret
I.e. accessing the m_data member of 'v', which is given only as its
address in %rdi, i.e. passed by memory. All as intended.
Ciao,
Michael.