當前位置:才華齋>計算機>C語言>

C函數的調用過程

C語言 閲讀(3.02W)

在C代碼中通過asm或__asm__嵌入一些彙編代碼,如進行系統調用,使用寄存器以提高性能能,需要對函數調用過程中的堆棧幀(Stack Frame)、CPU寄存器、GCC inlie assembly等了如指掌。現在看看函數調用過程吧。

C函數的調用過程
C函數的調用過程

  1. Linux 進程虛擬地址空間

以32位操作系統為例,下面是Linux進程地址空間佈局:

32位虛擬地址空間的高1GB的空間是留給操作系統內核的,棧由高地址到低地址向下增長,堆由低地址到高地址向上增長。

C中如 malloc 等分配的`內存在堆中分配。初始化了的靜態變量和全局變量放在Data段中。未初始化的全局變量和局部靜態變量放在Bss段中,更準確的説是在Bss段為它們預留了空間。非靜態局部變量是在函數調用過程中暫存在棧上的。

 2. 函數的堆棧幀

棧在程序運行中具有舉足輕重的地位。最重要的,棧保存了一個函數調用所需要的維護信息,被稱為堆棧幀(Stack Frame),一個函數(被調函數)的堆棧幀一般包括下面幾個方面的內容:

(1) 函數參數,默認調用慣例情況下從右向左的順序依次把參數壓入棧中。由函數調用方執行。

(2) 函數的返回地址,即調用方調用此函數(如call func1)的下一條指令的地址。函數調用方(call指令)執行。

(3) 保存調用方函數的EBP寄存器,即將調用方函數的EBP壓入堆棧,並令EBP指向此棧中的地址:pushl %ebp; movl %esp, %ebp。由被調函數執行。

(4) 上下文:保存在函數調用過程中需要保持不變的寄存器(函數調用方的),如ebx,esi,edi等。由被調函數執行。

(5) 臨時變量,如非靜態局部變量。

下面是一個函數的堆棧幀結構圖:

壓入函數參數和返回地址的過程是由函數調用方在調用函數之前將其壓入棧中,每個函數執行後首先要執行的就是把函數調用方的EBP寄存器壓入棧中,之後是在棧上開闢一些空間存放局部變量,最後把要保存的寄存器壓入棧中。