GCC忽略cdecl吗?

5

我在Linux x86上使用gcc。 我的程序将指向C函数的指针导出给LLVM JIT函数。调用约定是cdecl。它在Windows上的MingW上运行良好。但在Linux x86平台上会发生奇怪的事情。导出的C函数的反汇编代码如下:

push   ebp
mov    ebp,esp
push   ebx
sub    esp,0x34
mov    eax,0xfffffffc
mov    eax,DWORD PTR gs:[eax]
mov    eax,DWORD PTR [eax+0x1c]
mov    eax,DWORD PTR [eax]
mov    eax,DWORD PTR [eax+0x28]
mov    edx,DWORD PTR [ebp+0xc]
shl    edx,0x4
add    eax,edx
mov    DWORD PTR [ebp-0xc],eax
mov    edx,DWORD PTR ds:0x8e49940
mov    ebx,DWORD PTR [ebp+0x8]
lea    eax,[ebp-0x20]
mov    ecx,DWORD PTR [ebp-0xc]
mov    DWORD PTR [esp+0xc],ecx
mov    ecx,DWORD PTR [ebp+0x10]
mov    DWORD PTR [esp+0x8],ecx
mov    DWORD PTR [esp+0x4],edx
mov    DWORD PTR [esp],eax
call   0x8090f6f <SoCreateArray(DVM_VirtualMachine_tag*, int, DVM_TypeSpecifier_tag*)>
sub    esp,0x4
mov    eax,DWORD PTR [ebp-0x20]
mov    edx,DWORD PTR [ebp-0x1c]
mov    DWORD PTR [ebx],eax
mov    DWORD PTR [ebx+0x4],edx
mov    eax,DWORD PTR [ebp+0x8]
mov    ebx,DWORD PTR [ebp-0x4]
leave
ret    0x4

以下是 C 语言的源代码:

DVM_ObjectRef SoNewArray(BINT ty,BINT dim)
{
    DVM_TypeSpecifier *type
        = &curthread->current_executable->executable->type_specifier[ty];
    DVM_ObjectRef barray;
    barray = SoCreateArray(curdvm, dim, type);
    return barray;
}

请注意反汇编代码的最后一条指令是“ret 0x4”,这意味着该函数本身清除堆栈,并且不是一个cdecl函数!更重要的是,即使我像这样声明C函数:

DVM_ObjectRef SoNewArray(BINT ty,BINT dim) attribute((cdecl));

结果也是相同的。也许GCC优化了我的代码,自动使用stdcall,忽略调用约定?

我的GCC命令是

gcc -Wall -fexceptions -Wfatal-errors -g


我还发现这个程序在“call”指令之前也会推送eax(mov DWORD PTR [esp],eax)。如果我编译一个简单的“hello world” C程序,它在“call”之前不会推送eax。 - Menooker
那么最终,GCC 是否会忽略 __cdecl 呢?仍未得到答复。 - mireazma
2个回答

1

我的64位Linux上的gcc 5.4.0需要__attribute__((__cdecl__))

#ifdef __GNUC__
#define _cdecl __attribute__((__cdecl__))
#endif

//sometime later
int _cdecl AddItemVar(void *AContext,void *AFun,long ACfg1,...);

这段代码最初来自 __BORLANDC__,但也可以使用 __WATCOMC__ 和 __MSVC__ 进行编译。编译会产生以下警告:

../../LIB/DevOS.C/DevOS.h:242:64: 警告:忽略 ‘cdecl’ 属性 [-Wattributes]


1

https://www.zhihu.com/question/38726507

这是来自知乎的答案,感谢RednaxelaFX @ zhihu。我发现问题的原因实际上是该函数返回了一个结构体而不是基本类型。 请看函数声明:
DVM_ObjectRef SoNewArray(BINT ty,BINT dim)

DVM_ObjectRef是一个结构体。当x86 gcc处理像上面这样的函数时,它实际上生成:

DVM_ObjectRef SoNewArray(DVM_ObjectRef * ret,BINT ty,BINT dim)

查看有关x86调用约定的更多详细信息:

http://www.angelcode.com/dev/callconv/callconv.html


1
知乎是中国的Stack Exchange,但Stack Overflow是全球最大的程序员问答社区。 - Chen Li

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接