函數調用過程描述

在一個函數調用另一個函數過程中到底發生了什麼?

舉例,函數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在返回前自行處理的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章