在一个函数调用另一个函数过程中到底发生了什么?

举例,函数A调用了函数B,形如

int A(void)

{

          int i=B(int arg1,int arg2);

          return i;

}

我想描述下在调用B这个过程中所发生的故事:

这里是cdcel的调用方式

1,将传递给B的参数压入堆栈,压入顺序为从右向左,先将arg2压入,然后压入arg1

2,call B--调用函数B。这个过程会将B函数后执行后的地址,即return 的地址压入堆栈。然后前IP改为函数B的地址。开始执行B。

3,函数B在执行时,也要做些准备工作。

         a,保存ebp,因为ebp总是被我们用来保存函数执行前,即A的esp值。执行完B后我们要用ebp恢复esp;同样A对它的上层函数也是一样的过程。

                    push ebp;

         b,保存esp到ebp中。

                     mov ebp,esp

          c,堆栈中通过减少esp的值来空出空间保存B的局部变量,比如大小为0c2h。

                      sub esp,0c2h

          d,保存要使用到的寄存器值,如ebx,esi,edi

                      push ebx

                      push esi  

                      push edi

          d,将局部变量初始化为0cccccccch----0cch是int 3指令的机器码,这里把这部分空间初始为int 3主要是因为这些局部变量是不能被执行,但如果程序意外要执行它们就会引发一个调试中断来提示开发者。

                      lea edi,[ebp-0cch]

                      mov ecx,33h

                      mov eax,0cccccccc

                      rep stos dword ptr [edi]               ;串写入

                这里我们把从ebp-0cch开始的区域都初始化为0cch

              d,开始执行函数体的正常功能。在执行中如果要取得A传递来的参数。参数的获取是ebp+12字节为第二个参数,ebp+8为第一个参数(倒序插入),依次增加。最后ebp+4正好是我们保存的返回地址。               最后在处理中我们要将函数的返回值,将返回值放在eax中,外部(A)通过eax得到返回的值。    

              e,恢复ebx,esi,edi,esp,ebp,最后返回。:

                    pop edi

                    pop esi

                    pop ebx

                    mov esp,ebp

 

                    pop ebp

                    ret

                               

    这样一个完整的函数调用就结束了,A继续执行。。。。

 

 

 

继续执行中。。。。。。。。。。。。。。。。。。。。。。。。。

还在执行中。。。。。。。。。。。。。。。。

快结束 了。。。。。。。。。。。。。。。!!!

马上就要结束 了。。。。。。。。。。。。。。。。。。

啊!函数A结束了

C函数继续执行中!!!!!!!!!!! - -!

: )     

对于_stdcall方式的调用,堆栈是由被调用函数B在返回前自行处理的。