• 汇编角度看函数返回大对象原理


    汇编角度看函数返回大对象原理

    Win32

    测试代码

    C++
    struct ABCED
    {
            int a;
            int b;
            int c;
            int d;
    };
    ABCED TestABC()
    {
            ABCED aa;
            aa.a = 1;
            aa.b = 32;
            return aa;
    }
    MVoid TestA()
    {
            TestABC();
            return;
    }

     来看下汇编代码

    TestA()

    C++
    00D70D30  push        ebp 
    00D70D31  mov         ebp,esp 
    00D70D33  sub         esp,0F4h 
    00D70D39  push        ebx 
    00D70D3A  push        esi 
    00D70D3B  push        edi 
    00D70D3C  lea         edi,[ebp+FFFFFF0Ch] 
    00D70D42  mov         ecx,3Dh 
    00D70D47  mov         eax,0CCCCCCCCh 
    00D70D4C  rep stos    dword ptr es:[edi] 
    00D70D4E  mov         eax,dword ptr ds:[023100B4h] 
    00D70D53  xor         eax,ebp 
    00D70D55  mov         dword ptr [ebp-4],eax 
    00D70D58  lea         eax,[ebp+FFFFFF10h] 
    00D70D5E  push        eax 
    00D70D5F  call        00D70DB0 
    00D70D64  add         esp,4 
    00D70D67  mov         ecx,dword ptr [eax] 
    00D70D69  mov         dword ptr [ebp+FFFFFF28h],ecx 
    00D70D6F  mov         edx,dword ptr [eax+4] 
    00D70D72  mov         dword ptr [ebp+FFFFFF2Ch],edx 
    00D70D78  mov         ecx,dword ptr [eax+8] 
    00D70D7B  mov         dword ptr [ebp+FFFFFF30h],ecx 
    00D70D81  mov         edx,dword ptr [eax+0Ch] 
    00D70D84  mov         dword ptr [ebp+FFFFFF34h],edx 
    00D70D8A  pop         edi 
    00D70D8B  pop         esi 
    00D70D8C  pop         ebx 

    TestABC()

    C++
    00D70DB0  push        ebp 
    00D70DB1  mov         ebp,esp 
    00D70DB3  sub         esp,0DCh 
    00D70DB9  push        ebx 
    00D70DBA  push        esi 
    00D70DBB  push        edi 
    00D70DBC  lea         edi,[ebp+FFFFFF24h] 
    00D70DC2  mov         ecx,37h 
    00D70DC7  mov         eax,0CCCCCCCCh 
    00D70DCC  rep stos    dword ptr es:[edi];把函数栈空间初始化0xCCCCCCCC
    00D70DCE  mov         eax,dword ptr ds:[023100B4h] 
    00D70DD3  xor         eax,ebp 
    00D70DD5  mov         dword ptr [ebp-4],eax 
    00D70DD8  mov         dword ptr [ebp-18h],1 
    00D70DDF  mov         dword ptr [ebp-14h],20h 
    00D70DE6  mov         eax,dword ptr [ebp+8] 
    00D70DE9  mov         ecx,dword ptr [ebp-18h];ecx = 1 
    00D70DEC  mov         dword ptr [eax],ecx  ;AA.a;[ebp+8]=1
    00D70DEE  mov         edx,dword ptr [ebp-14h] ;edx = 0x20
    00D70DF1  mov         dword ptr [eax+4],edx  ;AA.b;[ebp + 12] = 0x20
    00D70DF4  mov         ecx,dword ptr [ebp-10h];AA.c 
    00D70DF7  mov         dword ptr [eax+8],ecx  ;;[ebp + 16]
    00D70DFA  mov         edx,dword ptr [ebp-0Ch]  ;AA.d
    00D70DFD  mov         dword ptr [eax+0Ch],edx  ;;[ebp + 20]
    00D70E00  mov         eax,dword ptr [ebp+8] ;[ebp+8] 也就是TestA ebp+FFFFFF28h也就是
                            ;也就是TestA ebp-D8,

    这就跟上边联系起来了,虽然TestA()里边什么也没有定义,也可以的出来栈空间还是分配了具体的空间,所以这里建议大家不要轻易返回大空间对象。接下来我们看下arm64的做法是否一致的

    arm64

    C++
    struct ABCED
    {
            int a;
            int b;
            int c;
            int d;
    };
    ABCED TestABC()
    {
            ABCED aa;
            aa.a = 1;
            aa.b = 32;
            return aa;
    }
    void TestA()
    {
            TestABC();
            return;
    }

    TestA

    Assembly language
    0x100003c6c <+0>:  sub    sp, sp, #0x20
    0x100003c70 <+4>:  stp    x29, x30, [sp, #0x10]
    0x100003c74 <+8>:  add    x29, sp, #0x10
    0x100003c78 <+12>: bl     0x100003c48               ; TestABC at main.mm:20
    0x100003c7c <+16>: str    x0, [sp];返回值ABCED.a, ABCED.b
    0x100003c80 <+20>: str    x1, [sp, #0x8];返回值ABCED.c, ABCED.d
    0x100003c84 <+24>: ldp    x29, x30, [sp, #0x10]
    0x100003c88 <+28>: add    sp, sp, #0x20;恢复栈
    0x100003c8c <+32>: ret   
     

    TestABC

    Assembly language
     0x100003c48 <+0>:  sub    sp, sp, #0x10
    0x100003c4c <+4>:  mov    w8, #0x1
    0x100003c50 <+8>:  str    w8, [sp];1 保存sp + 0
    0x100003c54 <+12>: mov    w8, #0x20
    0x100003c58 <+16>: str    w8, [sp, #0x4]; 32保存在sp + 4
    0x100003c5c <+20>: ldr    x0, [sp];把 ABCED.a, ABCED.b 保存x0
    0x100003c60 <+24>: ldr    x1, [sp, #0x8];;把 ABCED.c, ABCED.c 保存x1
    0x100003c64 <+28>: add    sp, sp, #0x10 ;函数栈返回
    0x100003c68 <+32>: ret   
     

    arm64汇编同样也可以看的出来,在TestA并没有分配对象空间,但是汇编代码上看,确实给其返回分配了空间,所以同样建议不要返回大空间对象,如果需要传递可以传递指针

  • 相关阅读:
    C#根据DataTable中的不同值为asp:DataGrid中的不同行或单元格设置不同的颜色
    单端口RAM实现FIFO
    压缩sql server日志的方法
    Linux:redis集群(3.*版本 和 5.*版本)搭建方法
    promise怎么用?promise的各种使用方法及理解?
    【.NET】聊聊 IChangeToken 接口
    QT中QSS设置的三种方法
    Linux系统firewalld防火墙的应用实操(对外端口开放使用,对内端口限制ip地址使用,不使用端口默认关闭)
    前端工程化
    智工教育:公务员网上报名确认事项与流程的状态标识
  • 原文地址:https://blog.csdn.net/c553110519/article/details/126648733