GCC忽略了cdecl?

时间:2015-12-20 10:22:35

标签: gcc calling-convention

我在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)属性((cdecl));

resule是一样的。也许GCC优化我的代码,并自动使用stdcall,忽略调用约定?

我的GCC命令是

gcc -Wall -fexceptions -Wfatal-errors -g

2 个答案:

答案 0 :(得分:1)

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

这是来自&#34; Zhihu&#34;,一个中文&#34; Stackoverflow&#34;的回答。感谢 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 :(得分:0)

我在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]