my understanding of the x86_64 ABI is that the following structure
should be passed in registers:
struct data {
unsigned int x;
unsigned int y;
unsigned long z;
};
but when I compile:
#include <stdio.h>
struct data {
unsigned int x : 32;
unsigned int y : 32;
unsigned long dummy : 64;
} ;
#ifdef __cplusplus
extern "C" int foo (data t);
#else
extern int foo (struct data t);
#endif
#ifndef __cplusplus
struct
#endif
data d;
int
main (int argc, char* argv[])
{
d.x = 1; d.y = 2;
printf ("an integer %d", foo(d));
return 0;
}
I get different results, depending on whether I compile it as C or C+
+ code. I'm using gcc 4.1.1 (but the same happens with 3.4.5).
In C I get:
main:
.LFB12:
subq $8, %rsp
.LCFI0:
movl $1, d+8(%rip)
movl $2, d+12(%rip)
movq d(%rip), %rdi
movq d+8(%rip), %rsi
call foo
so the argument gets passed in registers.
But in C++ the result is different and the data structure is passed
on the stack.
main:
.LFB13:
subq $24, %rsp
.LCFI0:
movl $1, d+8(%rip)
movq d(%rip), %rdi
movl $2, d+12(%rip)
movq d+8(%rip), %rsi
movq %rdi, (%rsp)
movq %rsi, 8(%rsp)
call foo
My understanding of the ABI is that the data structure should be
passed in registers, but in any case the behavior should be the same
for C and C++ when data is POD. In the example if foo was a C
function the code produced by g++ would be wrong. In this case it
would also be very dangerous because the data structure happens to be
_also_ in the right registers, but I expect small changes to the code
to make it fail.
Unless g++ is actually passing the argument in registers and what's
wrong is the spurious pushes onto the stack.
Maurizio Vitale