【问题标题】:GCC ignores cdecl?GCC 忽略 cdecl?
【发布时间】:2015-12-20 10:22:35
【问题描述】:

我在 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));

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

我的 GCC 命令是

gcc -Wall -fexceptions -Wfatal-errors -g

【问题讨论】:

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

标签: gcc calling-convention


【解决方案1】:

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

这里是来自中文“Stackoverflow”的“知乎”的回答。感谢 RednaxelaFX@知乎。我发现这个问题的真正原因是该函数返回一个结构而不是基本类型。 见函数声明:

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

【讨论】:

  • 知乎是中文Stack Exchange,但是栈溢出
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2011-02-17
    • 2023-03-28
    • 2018-04-16
    • 1970-01-01
    • 2013-07-10
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 2021-07-05
    相关资源
    最近更新 更多