对于调用函数返回结构约定 [英] Calling convention for function returning struct

查看:131
本文介绍了对于调用函数返回结构约定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关下列C code:

 结构_AStruct {
    int类型的;
    INT B:
    浮℃;
    浮D组;
    INTê;
};typedef结构_AStruct AStruct;AStruct test_callee5();
无效test_caller5();无效test_caller5(){
    AStruct G = test_callee5();
    AStruct H = test_callee5();
}

我得到以下拆装的Win32:

  _test_caller5:
  00000000:LEA EAX,[ESP-14H]
  00000004:分ESP,14H
  00000007:推EAX
  00000008:拨打_test_callee5
  0000000D:LEA ECX,[ESP + 4]
  00000011:推ECX
  00000012:拨打_test_callee5
  00000017:ADD ESP,代上
  0000001A:RET

和为linux32镜像:

  00000000< test_caller5计算值:
   0:推%EBP
   1:MOV%ESP,EBP%
   3:分$ 0x38,ESP%
   6:LEA 0xffffffec(EBP%),%EAX
   9:MOV EAX%(%ESP)
   C:叫D< test_caller5 + 0xd中>
  11:子$为0x4,ESP%;;;;;;;;;;请注意,这额外的子;;;;;;;;;;;;
  14:LEA 0xffffffd8(EBP%),%EAX
  17:MOV EAX%(%ESP)
  1A:拨打1B< test_caller5 + 0x1b>
  1F:子$为0x4,ESP%;;;;;;;;;;请注意,这额外的子;;;;;;;;;;;;
  22:离开
  23:RET

我想了解主叫呼叫后的行为方式的差异。
为什么在linux32镜像,来电者做这些额外的潜艇?

我会假设这两个指标将遵循cdecl调用约定。不CDECL定义调用约定返回结构的函数吗?!

编辑:

我加被叫方的实现。果然,你可以看到linux32镜像,被叫方弹出它的参数,而在Win32被叫方不:

  AStruct test_callee5()
{
    AStruct S = {0};
    返回S;
}

Win32的拆卸:

  test_callee5:
  00000000:MOV EAX,DWORD PTR [ESP + 4]
  00000004:XOR ECX,ECX
  00000006:MOV DWORD PTR [EAX],0
  0000000C:MOV DWORD PTR [EAX + 4],ECX
  0000000F:MOV DWORD PTR [EAX + 8],ECX
  00000012:MOV DWORD PTR [EAX + 0CH],ECX
  00000015:MOV DWORD PTR [EAX + 10H],ECX
  00000018:RET

linux32镜像,拆卸:

  00000000< test_callee5计算值:
   0:推%EBP
   1:MOV%ESP,EBP%
   3:分$为0x20,ESP%
   6:MOV,位于0x8(%EBP),EDX%
   9:MOVL $ 0x0,0xffffffec(EBP%)
  10:MOVL $ 0x0,0xfffffff0(EBP%)
  17:MOVL $ 0x0,0xfffffff4(EBP%)
  1E:MOVL $ 0x0,0xfffffff8(EBP%)
  25:MOVL $ 0x0,0xfffffffc(EBP%)
  2C:MOV 0xffffffec(EBP%),%EAX
  2F:MOV EAX%(%EDX)
  31:MOV 0xfffffff0(%EBP),EAX%
  34:MOV EAX%,为0x4(%EDX)
  37:MOV 0xfffffff4(%EBP),EAX%
  3A:MOV EAX%,位于0x8(%EDX)
  3D:MOV 0xfffffff8(%EBP),EAX%
  40:MOV EAX%,位于0xC(%EDX)
  43:MOV 0xfffffffc(%EBP),EAX%
  46:MOV EAX%,为0x10(%EDX)
  49:MOV EDX%,%EAX
  4B:离开
  4C:RET $为0x4 ;;;;;;;;;;;;;;请注意,这;;;;;;;;;;;;;;


解决方案

有没有单一的的cdecl调用约定。它是由编译器和操作系统定义

此外读书,我没有真正确定的惯例实际上是不同的&MDASH大会;在这两种情况下调用者的输出作为额外的参数提供缓冲。这只是GCC选择了不同的指令(第二个加分很奇怪;这是code优化)。

For the following C code:

struct _AStruct {
    int a;
    int b;
    float c;
    float d;
    int e;
};

typedef struct _AStruct AStruct;

AStruct test_callee5();
void test_caller5();

void test_caller5() {
    AStruct g = test_callee5();
    AStruct h = test_callee5();    
}

I get the following disassembly for Win32:

_test_caller5:
  00000000: lea         eax,[esp-14h]
  00000004: sub         esp,14h
  00000007: push        eax
  00000008: call        _test_callee5
  0000000D: lea         ecx,[esp+4]
  00000011: push        ecx
  00000012: call        _test_callee5
  00000017: add         esp,1Ch
  0000001A: ret

And for Linux32:

00000000 <test_caller5>:
   0:  push   %ebp
   1:  mov    %esp,%ebp
   3:  sub    $0x38,%esp
   6:  lea    0xffffffec(%ebp),%eax
   9:  mov    %eax,(%esp)
   c:  call   d <test_caller5+0xd>
  11:  sub    $0x4,%esp  ;;;;;;;;;; Note this extra sub ;;;;;;;;;;;;
  14:  lea    0xffffffd8(%ebp),%eax
  17:  mov    %eax,(%esp)
  1a:  call   1b <test_caller5+0x1b>
  1f:  sub    $0x4,%esp   ;;;;;;;;;; Note this extra sub ;;;;;;;;;;;;
  22:  leave
  23:  ret

I am trying to understand the difference in how the caller behaves after the call. Why does the caller in Linux32 do these extra subs?

I would assume that both targets would follow the cdecl calling convention. Doesn't cdecl define the calling convention for a function returning a structure?!

EDIT:

I added an implementation of the callee. And sure enough, you can see that the Linux32 callee pops its argument, while the Win32 callee does not:

AStruct test_callee5()
{
    AStruct S={0};
    return S;
}

Win32 disassembly:

test_callee5:
  00000000: mov         eax,dword ptr [esp+4]
  00000004: xor         ecx,ecx
  00000006: mov         dword ptr [eax],0
  0000000C: mov         dword ptr [eax+4],ecx
  0000000F: mov         dword ptr [eax+8],ecx
  00000012: mov         dword ptr [eax+0Ch],ecx
  00000015: mov         dword ptr [eax+10h],ecx
  00000018: ret

Linux32 disassembly:

00000000 <test_callee5>:
   0:   push   %ebp
   1:   mov    %esp,%ebp
   3:   sub    $0x20,%esp
   6:   mov    0x8(%ebp),%edx
   9:   movl   $0x0,0xffffffec(%ebp)
  10:   movl   $0x0,0xfffffff0(%ebp)
  17:   movl   $0x0,0xfffffff4(%ebp)
  1e:   movl   $0x0,0xfffffff8(%ebp)
  25:   movl   $0x0,0xfffffffc(%ebp)
  2c:   mov    0xffffffec(%ebp),%eax
  2f:   mov    %eax,(%edx)
  31:   mov    0xfffffff0(%ebp),%eax
  34:   mov    %eax,0x4(%edx)
  37:   mov    0xfffffff4(%ebp),%eax
  3a:   mov    %eax,0x8(%edx)
  3d:   mov    0xfffffff8(%ebp),%eax
  40:   mov    %eax,0xc(%edx)
  43:   mov    0xfffffffc(%ebp),%eax
  46:   mov    %eax,0x10(%edx)
  49:   mov    %edx,%eax
  4b:   leave
  4c:   ret    $0x4  ;;;;;;;;;;;;;; Note this ;;;;;;;;;;;;;;

解决方案

There is no single "cdecl" calling convention. It is defined by the compiler and operating system.

Also reading the assembly I am not actually sure the convention is actually different—in both cases the caller is providing buffer for the output as extra argument. It's just that gcc chose different instructions (the second extra sub is strange; is that code optimized?).

这篇关于对于调用函数返回结构约定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆