4byte structures that are passed as parameters to a fastcall routine will get passed as registers. This does not match the original fastcall convention, which passes such structures on the stack. Compiling this code: #include <stdio.h> typedef struct { int a; } my_struct; int __attribute__((fastcall)) foo(my_struct s, int b) { return s.a + b; } main() { my_struct ss; ss.a = 1; printf("\nfoo = %d.\n",foo(ss,2)); } Results in: . . movl $1, -12(%ebp) movl -12(%ebp), %ecx movl $2, %edx call _foo . . and . . .globl _foo _foo: pushl %ebp movl %esp, %ebp subl $24, %esp movl %ecx, -12(%ebp) movl %edx, -16(%ebp) movl -12(%ebp), %eax addl -16(%ebp), %eax leave ret With GCC. Using other compilers that support fastcall will pass the struct value on the stack.
I verified that it isn't fixed in gcc 4.3.0.
From http://msdn2.microsoft.com/en-us/library/6xa169sk(VS.80).aspx "The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left." But it isn't clear if it applies to structure/union. We tested all MS compilers we have and verified that the above doesn't apply to structure/union. To make fastcall compatible with MS compilers, we should only put scalar arguments in ECX and EDX.
A patch is posted at http://gcc.gnu.org/ml/gcc-patches/2007-11/msg00531.html
From "info gcc", `fastcall' On the Intel 386, the `fastcall' attribute causes the compiler to pass the first argument (if of integral type) in the register ECX ^^^^^^^^^^^^^^^^^^^ and the second argument (if of integral type) in the register EDX. ^^^^^^^^^^^^^^^^^^^ Subsequent and other typed arguments are passed on the stack. The called function will pop the arguments off the stack. If the number of arguments is variable all arguments are pushed on the stack. It looks like gcc document follows MS compiler and we didn't implement it correctly.
The correct patch is at http://gcc.gnu.org/ml/gcc-patches/2007-11/msg00885.html
We have changed fastcall behavior from gcc 3.4 to 4.1. For --- #define FASTCALL __attribute((fastcall)) double FASTCALL f_dii( double p1d, int p2i, int p3i ){ return p1d + (double)p2 i + (double)p3i; } int test_x; int test_y; double test_d1; void caller( void ){ f_dii( test_d1, test_x, test_y ); } --- Gcc 3.4 doesn't pass the first 2 integral parameters in ecx/edx and gcc 4.1 does.
(In reply to comment #6) > We have changed fastcall behavior from gcc 3.4 to 4.1. For > > --- > #define FASTCALL __attribute((fastcall)) > > double FASTCALL f_dii( double p1d, int p2i, int p3i ){ return p1d + > (double)p2 > i + (double)p3i; } > > int test_x; > int test_y; > double test_d1; > > void caller( void ){ > f_dii( test_d1, test_x, test_y ); > } > --- > > Gcc 3.4 doesn't pass the first 2 integral parameters in ecx/edx and gcc > 4.1 does. > This patch http://gcc.gnu.org/ml/gcc-patches/2005-01/msg00541.html fixes this fast call bug by changing the abi.
Subject: Bug 34001 Author: hjl Date: Wed Nov 28 01:20:34 2007 New Revision: 130488 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=130488 Log: 2007-11-27 H.J. Lu <hongjiu.lu@intel.com> Joey Ye <joey.ye@intel.com> PR target/34001 * config/i386/i386.c (function_arg_32): Don't pass aggregate arguments in ECX/EDX for fastcall. Modified: trunk/gcc/ChangeLog trunk/gcc/config/i386/i386.c
Fixed in gcc 4.3.