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.