函數調用堆棧的過程

本篇來分析函數調用的過程:

通過下面一個簡單的例子來進入話題:

#include<stdio.h>
int sum(int a,int b)
{
	int tmp=0;
	tmp=a+b;
	return tmp;
}

int main()
{
	int a=10;
	int b=20;
	int ret=0;

	ret=sum(a,b);
	printf("ret=%d\n",ret);
	return 0;
}

首先,先從main函數開始,查看main()函數的反彙編代碼,進去之後會發現在一開始就看到如下部分:


那這一部分是幹什麼的呢?先留個疑問,等會解決!

緊接着,繼續看反彙編,如下圖


畫出在棧中的整個過程:


呃,畫圖的確有點麻煩,不過越畫越清楚,^O^

整個函數的調用,結合上面兩張圖就基本明白了。那現在說一下剛開始的問題,在第一張圖中也做了一點標註。對於每個函數的剛開始都會出現基本類似的指令。這一大堆指令總結起來就幹了四件事情:

第一:將調用方的棧底地址入棧。====》push  ebp

第二:讓原本指向調用方棧底的ebp指向當前函數的棧底。====》mov   ebp,esp

第三:給當前函數開闢棧幀。====>sub   esp,44h

第四:對開闢的棧幀進行初始化。初始化的大小不一定。====>rep   stos  

所以對於sum函數我們可以理解,但是在main函數剛開始也有這些指令,不由地,我們知道,main函數也是通過一個函數來進行調用的,所以也需要上面這四個步驟!!此時也就可以回答圖二中我畫??的地方咯,它一定存的是調用main函數的函數棧底地址。是不是很清楚呀^O^

趁熱打鐵,自己寫一下整個過程吧!

#include<stdio.h>
int sum(int a,int b)
{
	/*
	push ebp
	mov ebp,esp
	sub esp,44h
	push ebx
	push esi
	push edi
	lea edi,[ebp-44h]
	mov ecx,11h
	mov eax,0xccccccch
	rep stos ===>[esp,ebp]=0xcccccccc
	*/
	int tmp=0;//mov dword ptr[ebp-4],0
	tmp=a+b;
	/*
	mov eax,dword ptr[ebp+8]
	add eax,dword ptr[ebp+0ch]
	mov dword ptr[ebp-4],eax
	*/
	return tmp;//mov dword ptr[ebp-4],eax
}
/*
mov eax,dword ptr[ebp-4]
mov esp,ebp
pop ebp
ret
*/

int main()
{
	/*
	push ebp
	mov ebp,esp
	sub esp,44h
	push ebx
	push esi
	push edi
	lea edi,[ebp-44h]
	mov ecx,11h
	mov eax,0xccccccch
	rep stos ===>[esp,ebp]=0xcccccccc
	*/
	int a=10;//mov dword ptr[ebp-4],0Ah
	int b=20;//mov dword ptr[ebp-8],14h
	int ret=0;//mov dword ptr[ebp-0Ch],0
	ret=sum(a,b);
	/*
	mov eax,ptr[ebp-8]
	push eax
	mov ebx,ptr[ebp-4]
	push ebx
	push ecx
	call sum
	add esp,8
	mov dword ptr[ebp-0ch],eax
	*/
	printf("ret=%d\n",ret);
	return 0;
}

總結一下吧~

1、函數的運行都是在棧上開闢內存。

2、棧是通過esp(棧頂指針)、ebp(棧底指針)兩個指針來標識的。

3、對於棧上的訪問都是通過棧底指針的偏移來訪問的。

4、在call一個函數時,有兩件事情要做:先將調用函數的下一行指令的地址壓入棧中;再進行跳轉。

5、在函數調用時檢查函數是否申明、函數名是否相同、函數的參數列表是否匹配、函數的返回值多大。

①如果  【函數的返回值<=4個字節】,則返回值通過寄存器eax帶回。

②如果  【4<函數的返回值<=8個字節】,則返回值通過兩個寄存器eax和edx帶回。

③如果  【函數的返回值>8個字節】,則返回值通過產生的臨時量帶回。

6、函數結束ret指令幹了兩件事:先出棧;再將出棧的值放到CPU的PC寄存器中。因爲PC寄存器中永遠放的是下一次執行指令的地址,所以就順理成章的在函數調用完之後依舊接着原來的代碼繼續執行。

END~


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