Bug 41013 - Fastcall calling convention is incompatible with Windows
Summary: Fastcall calling convention is incompatible with Windows
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.4.1
: P3 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-08-09 13:37 UTC by mikulas
Modified: 2013-05-25 15:10 UTC (History)
2 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description mikulas 2009-08-09 13:37:47 UTC
In Windows, fastcall calling convention is implemented in the following way:
* an argument that has integer type with size less-or-equal than 4 bytes is eligible for fastcall
* the first argument that is eligible for fastcall is passed in ECX
* the second argument that is eligible for fastcall is passed in EDX

GCC implementes it badly, structures and 64-bit integer arguments are not correctly passed in registers but they incorrectly increase the register number in "function_arg_advance_32" and further arguments eligible for fastcall are not passed in registers.

Example:

struct s {
        int a;
};

int __attribute__((fastcall,noinline)) f(struct s s, int a1, int a2)
{
        printf("args: %d, %d, %d\n", a1, a2, s.a);
        return 0;
}

int main()
{
        struct s s = { 3 };
        f(s, 1, 2);
        return 0;
}

--- on Windows, s goes on the stack, a1 goes in ECX and a2 goes in EDX.
--- in gcc, s goes on the stack (but it incorrectly increased a register number), a1 goes in EDX and a2 goes on the stack too because gcc runs out of fastcall registers.
Comment 1 mikulas 2009-08-09 13:39:49 UTC
"an argument that has integer type" should really be "an argument that has integer or pointer type" ... pointers are passed in registers too. Anything else isn't, I think.
Comment 2 mikulas 2009-08-11 20:48:44 UTC
Another inconsistency: struct { float f }; is returned in ST(0) in GCC and in EAX on Windows. struct { double f }; is returned in ST(0) in GCC and in EDX:EAX on Windows. See PR 41017 for more examples.

Another one: On Windows, structure with zero size ( struct { int a[0]; }) is treated like having size 4 when passing arguments and treated like being returned in registers (well, really, there is nothing returned because the structure is empty, but it differs from GCC: GCC will pass dummy return place argument and Windows won't).

Another one: struct { int a; int b[]; } is treated like having variable-size and allways returned by reference in GCC. In Windows b[] and b[0] seem to be equivalent and this is treated like having the size 4 and returned in EAX.

I also quite didn't get the purpose of MS_AGGREGATE_RETURN --- it seems to be doing the same thing as -freg-struct-return in current gcc code. How are these two supposed to differ? But it could be used to differentiate this zero-sized-member thing.