1. 程式人生 > >【18.7.27】函式呼叫過程的深度理解(棧幀)

【18.7.27】函式呼叫過程的深度理解(棧幀)

函式可以大大減少我們程式的程式碼量,使程式碼寫起來更加的簡潔,使程式碼思路更加清晰。是我們程式猿在編寫程式碼時必不可少的。
那麼函式的呼叫過程就非常的重要,今天讓我們來從一個深的角度去了解一下函式的呼叫過程。

函式的呼叫過程也可以叫做棧幀

棧幀的定義是:棧幀也叫過程活動記錄,是編譯器用來實現過程/函式呼叫的一種資料結構。
每一次函式的呼叫,都會在記憶體中為自己申請一塊空間,這個空間就叫函式執行時堆疊,也就是棧幀。這裡寫圖片描述
這塊空間就像棧一樣,都需要去維護,棧頂又暫存器ESP去維護,棧底呢就又暫存器EBP去維護。
接下來我們寫一個簡單的程式碼,去更加具體的瞭解我們的函式呼叫過程。
#include<stdio.h>
int main()
{
    int i = 20;
    int j = 30;
    int k = 0;
    k = Add(i,j);
    printf("%d\n",k);
    return 0;
}
int Add(int x,int y)
{//主函式呼叫Add函式去實現加法的功能
    int z = 0;
    z = x + y;
    return z;
}
開啟除錯,進入呼叫堆疊,看看函式的呼叫邏輯。這裡寫圖片描述
根據記憶體中棧的特點是由低到高,我們看出,main函式是被mainCRTStartup函式呼叫。開啟反彙編程式碼。在進去main函式到開始我們的程式碼前有這樣一段反彙編程式碼。

這裡寫圖片描述

我們把這段反彙編程式碼用影象形象的描述一下。這裡寫圖片描述
我們把E4轉化成十進位制,就是228,也就是說,把EBP-228的位置的地址給EDI,然後從EDI開始向高地址存放CCCCCCCC,一次4個位元組,存放39次,十進位制的57次,大小正好也是228.就是把這E4的空間大小,放57個CCCCCC進去,每個4位元組。這裡寫圖片描述
看一下記憶體,我們看一下這樣的結果,是不是我們所說的樣子

這裡寫圖片描述

然後我們接著看反彙編程式碼

這裡寫圖片描述

繼續畫圖

這裡寫圖片描述

進入CALL指令,我們就進入的Add函式的內部

這裡寫圖片描述

我們發現和呼叫main函式前,的準備工作幾乎是一致的。那就說明剛才main函式開始前的操作,是開闢函式空間時的準備工作。

這裡寫圖片描述
這裡寫圖片描述

從進入Add函式,為Add函式開闢了一塊空間,然後一頓操作,然後彈彈彈,就是將Add函式進行銷燬,這就是Add函式棧幀的銷燬。

這裡寫圖片描述

當Add函式執行完成以後,全部被彈出,ESP和EBP暫存器儲存的地址指向同一塊地區,執行EBP–main,把EBP直接彈回main函式中他需要維護的地方。EBP就繼續維護他的main函式去了。那我們就不難想,在main函式開始時,存的EBP就是為了,在main函式結束後,返回mainCRT函式中去,讓EBP繼續去維護mainCRT函式。然後call指令,將我們繼續帶回,剛才的的地方,完成下面的指令。走到這裡。一個函式的完整呼叫也就結束了。