Poedu_计算机基础_lesson06_20160902_函数调用过程 _作业

来源:互联网 发布:apache 不允许列目录 编辑:程序博客网 时间:2024/06/06 01:33

代码:

#include"stdio.h"

 

int main()

{

printf("I love sin!");

return 0;

}

注:在printf处下断点,按F5执行,右键点击进入反汇编,按F10逐句调试,F11逐过程调试(需要进入call内部,需要按F11)

反汇编(Release版):

printf("I love sin!");

EAX = 0102F6D0 EBX = 00879000 ECX = 00000000 EDX = 00000000 ESI = 75F36314 EDI = 75F36308 EIP = 00E21040ESP = 00AFFB0C EBP = 00AFFB50 EFL = 00000200

00E21040  push        offset string "I love sin!" (0E220F8h)参数入栈 

00E21045  call        printf (0E21010h)  

ESP = 00AFFB04  EBP = 00AFFB50

=>只进行了一次跳转,esp却上移了4字节

00E21010  push        ebp     =>保存栈顶,用于还原现场

00E21011  mov         ebp,esp =>栈底上移到栈顶的位置,保护数据

00E21013  push        esi  

    int _Result;

    va_list _ArgList;

    __crt_va_start(_ArgList, _Format);

    _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList);

00E21014  mov         esi,dword ptr [_Format]  

00E21017  push        1  

ESP = 00AFFAF8  EBP = 00AFFB00

00E21019  call        dword ptr [__imp____acrt_iob_func (0E220B0h)]  

ESP = 00AFFAF4 EBP = 00AFFB00

75E9CF70  mov         edi,edi  

ESP = 00AFFAF4 EBP = 00AFFB00

75E9CF72  push        ebp ==>存入ebp地址 

ESP = 00AFFAF0 EBP = 00AFFB00

75E9CF73  mov         ebp,esp=>ebp上移到esp位置 

ESP = 00AFFAF0EBP = 00AFFAF0

75E9CF75  imul        eax,dword ptr [ebp+8],38h  

75E9CF79  add         eax,75F352E0h  

ESP = 00AFFAF0 EBP = 00AFFAF0

75E9CF7E  pop         ebp  

ESP = 00AFFAF4 EBP = 00AFFB00

75E9CF7F  ret  

ESP = 00AFFAF8  EBP = 00AFFB00

00E2101F  add         esp,4  

00E21022  lea         ecx,[ebp+0Ch]  

00E21025  push        ecx  

00E21026  push        0  

00E21028  push        esi  

00E21029  push        eax  

ESP = 00AFFAF8  EBP = 00AFFB00

00E2102A  call        __local_stdio_printf_options (0E21000h)  

ESP = 00AFFAF8 EBP = 00AFFB00

00E2102F  push        dword ptr [eax+4]  

00E21032  push        dword ptr [eax]  

00E21034  call        dword ptr [__imp____stdio_common_vfprintf (0E220ACh)]  

00E2103A  add         esp,18h  

00E2103D  pop         esi  

    __crt_va_end(_ArgList);

    return _Result;

}

00E2103E  pop         ebp  

00E2103F  ret 

 

00E2104A  add         esp,4

return 0;

00E2104D  xor         eax,eax  

}

00E2104F  ret


注:本程序我并没有全部的逐过程调试(太多跳转了!!)

 

 

 

 

 

 

总结

 

 

   

===>可以发现,完成这个call指令之后,ebp的地址与进入call指令之前是相同的,也就是说,在执行完这个指令后,ebp回到了原现场,可以继续进行原来的操作。

  

===>当进行跳转后的另一函数体的执行时,都会出现这样的操作其目的是为了保护当前进行的程序所用到的数据,然后再跳至另一内存地址执行跳转之后的指令,即发生下图所示动作(当新函数有数据进入时,esp会继续上游,出栈时esp向ebp靠拢,当esp等于ebp时(即栈底等于栈顶),栈清空):

===>每次指令call指令跳转后,esp都会莫名的多出4个字节(一个地址),但是我们并未对其进行操作,为什么会多出来?而执行完call指令返回后,这4个字节又消失了,这又是为什么?4个字节刚好是一个地址,而其中保存的正是当前执行到的地址,为了能够在执行完call指令之内的程序时,可以回到原来的路,编译器自动为我们保存了该地址,在ret的时候自动返回。

  ===>关于参数入栈:

 

在开始的时候,程序即对参数进行了push的操作,说明我们的程序的参数同样也是保存在栈中进行使用的

0 0
原创粉丝点击