GCC文档中的x86 Function Attributes表示:
在32位和64位x86目标上,可以使用ABI属性来指示函数应使用哪个调用约定.
ms_abi
属性告诉编译器使用Microsoft ABI,而sysv_abi
属性告诉编译器使用System V ELF ABI,它在GNU/Linux和其他系统上使用.默认情况下,以Windows为目标时使用Microsoft ABI.在所有其他系统上,默认值为System V ELF ABI.
但请考虑以下C代码:
#include <assert.h>
#ifdef _MSC_VER
#define MS_ABI
#else
#define MS_ABI __attribute__((__ms_abi__))
#endif
typedef struct {
void *x, *y;
} foo;
static_assert(sizeof(foo) == 8, "foo must be an 8-byte structure");
foo MS_ABI f(void *x, void *y) {
foo rv;
rv.x = x;
rv.y = y;
return rv;
}
gcc -O2 -m32
将其编译为:
f:
mov eax, DWORD PTR [esp+4]
mov edx, DWORD PTR [esp+8]
mov DWORD PTR [eax], edx
mov edx, DWORD PTR [esp+12]
mov DWORD PTR [eax+4], edx
ret
但cl /O2
将其编译为:
_x$ = 8 ; size = 4
_y$ = 12 ; size = 4
_f PROC ; COMDAT
mov eax, DWORD PTR _x$[esp-4]
mov edx, DWORD PTR _y$[esp-4]
ret 0
_f ENDP
这些显然使用了不兼容的调用约定.MSDN上的Argument Passing and Naming Conventions表示:
返回值也被加宽到32位,并在EAX寄存器中返回,但8字节 struct 除外,它在EDX:EAX寄存器对中返回.较大的 struct 在EAX寄存器中作为指向隐藏返回 struct 的指针返回.
这意味着MSVC是正确的.那么,为什么GCC使用指向隐藏返回 struct 的指针方法,即使返回值是8字节 struct ?这是GCC中的一个bug,还是我不能像我想的那样使用ms_abi
?