分享

从汇编源码逐步分析函数调用过程

 喜欢站在山上 2020-12-17

C源码

#include 'stdio.h'

int test(int x, int y, double& z)

{

    z = x + y;

return 0;

}

void main()

{

double sum = 1.2;

    int a = 2 ,b = 3 , ret = 0;

ret = test(a, b, sum);

printf('ret:%d', ret);

}

对应的汇编代码

void main()

11:   {

寄存器          栈单元地址            栈单元内容或解释

00410990   push        ebp  //压入之前调用栈的栈底地址,栈元素增加1

00410991   mov         ebp,esp  //新栈空间的栈底地址EBP设置为增加的这个栈元素地址(即调用者栈栈帧的栈底地址)

00410993   sub         esp,54h   //分配54h 即84字节栈内存

00410996   push        ebx  //保存各寄存器内容

00410997   push        esi

00410998   push        edi

00410999   lea         edi,[ebp-54h] //取新分配内存的低地址

0041099C   mov         ecx,15h   //计数器设置15h, 及21个4字节

004109A1   mov         eax,0CCCCCCCCh  //写入eax, 0CCCCCCCCh表示初始化的内存

004109A6   rep stos    dword ptr [edi] //将eax内容写入内存地址,计数,写15h次。

12:       double sum = 1.2;

004109A8   mov         dword ptr [ebp-8],33333333h

004109AF   mov         dword ptr [ebp-4],3FF33333h

13:       int a = 2 ,b = 3 , ret = 0;

004109B6   mov         dword ptr [ebp-0Ch],2

004109BD   mov         dword ptr [ebp-10h],3

004109C4   mov         dword ptr [ebp-14h],0

//变量初始化, EBP-X 表示变量地址,先分配的变量减的少,后分配的减的多

14:       ret = test(a, b, sum);

004109CB   lea         eax,[ebp-8]

004109CE   push        eax

004109CF   mov         ecx,dword ptr [ebp-10h]

004109D2   push        ecx

004109D3   mov         edx,dword ptr [ebp-0Ch]

004109D6   push        edx

004109D7   call        @ILT+10(test) (0040100f) //跳转到test的函数执行,请先看test部分,test执行完

标记A

004109DC   add         esp,0Ch  //释放调用时压栈参数再看这边。

004109DF   mov         dword ptr [ebp-14h],eax //将返回值保存到栈临时变量

15:       printf('ret:%d', ret);  //此段不解释

004109E2   mov         eax,dword ptr [ebp-14h] 

004109E5   push        eax

004109E6   push        offset string 'ret:%d' (00426fd8)

004109EB   call        printf (00410910)

004109F0   add         esp,8

16:   }

004109F3   pop         edi //恢复各寄存器

004109F4   pop         esi

004109F5   pop         ebx

004109F6   add         esp,54h //释放临时变量

004109F9   cmp         ebp,esp  //此时两者应该相等

004109FB   call        __chkesp (00401170)

00410A00   mov         esp,ebp //恢复上层调用者栈顶

00410A02   pop         ebp  //恢复上层调用者栈底

00410A03   ret    //调转到上层调用者执行

至此主函数执行结束。

main ret后的代码

00401299   add         esp,0Ch

0040129C   mov         dword ptr [mainret],eax

0040129F   mov         edx,dword ptr [mainret]

004012A2   push        edx

004012A3   call        exit (00402360)

----------------------------------------------------------------------------------------------------------------------

Test函数源码

3:    int test(int x, int y, double& z)

4:    {

00401020   push        ebp

00401021   mov         ebp,esp

00401023   sub         esp,44h

00401026   push        ebx

00401027   push        esi

00401028   push        edi

00401029   lea         edi,[ebp-44h]

0040102C   mov         ecx,11h

00401031   mov         eax,0CCCCCCCCh

00401036   rep stos    dword ptr [edi]

5:        z = x + y;

00401038   mov         eax,dword ptr [ebp+8] //ebp+X引用调用者传入参数变量

0040103B   add         eax,dword ptr [ebp+0Ch]

0040103E   mov         dword ptr [ebp-4],eax //ebp-X 引用本函数块分配的变量

00401041   fild        dword ptr [ebp-4] //fild是将整数转化为长双精FP80压栈(压到st0

00401044   mov         ecx,dword ptr [ebp+10h] 

00401047   fstp        qword ptr [ecx] //fstp是将弹栈指令,将st0弹出。

6:        return 0;

00401049   xor         eax,eax

7:    }

0040104B   pop         edi  //各寄存器值出栈恢复

0040104C   pop         esi

0040104D   pop         ebx

0040104E   mov         esp,ebp //释放本函数栈空间

00401050   pop         ebp   //恢复EBP指针,同时ESP指针下移一个 push 指令ESP自动上移,pop自动下移。至此,栈空间又恢复到main函数的栈空间。

00401051   ret        //函数调用结束弹出栈顶元素(返回地址),跳转到此地址执行。请回到标记A处继续阅读。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多