一.前言
每一次函式呼叫都是一個程序,這個程序我們通常稱之為:函式的呼叫程序,
這個程序要為函式開辟堆疊空間,用于本次函式的呼叫中臨時變數的保存,現場保護,這塊堆疊空間就是函式堆疊幀,
實驗代碼:
#include<stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
int a = 10;
int b = 20;
int c = 0;
c = add(a, b);
printf("%d", c);
return 0;
}
二.實驗除錯
1.按F11進入單步除錯,在視窗處進入反匯編,

進入反匯編界面

三、函式堆疊幀的創建與銷毀
1.在除錯的時候我們要明白兩個暫存器ebp內部存盤的是堆疊底指標,esp存盤的是堆疊頂指標,
eip是程式計數器,存的是當前正在執行指令的下一條指令的地址
2.進入程式,一步一步進行除錯
(1).先看前三條
push ebp
mov ebp,esp
sub esp,0E4h
堆疊區是從下到上,由高地址到低地址,先將ebp入堆疊,在將esp移到和ebp相同的位置,在將esp的地址減掉0E4h

(2).再看三條操作
push ebx
push esi
push edi
繼續向 main()函式上方又壓入ebx,esi,edi,且esp也隨著壓入的資料而地址降低,

(3).繼續執行操作
lea edi,[ebp-24h]
mov ecx,9
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
第一條指令是將[ebp-0E4h]的值加載到edi當中,該地址是228個位元組的上方,
第二,三條指令分別是將9賦給到ecx,0CCCCCCCCh 賦給到eax,
第四條指令則是將從edi開始,向下的39hdword(就是39hdoubleword(兩個字),一共是228個位元組,就是最開始開辟的main函式堆疊幀大小)都賦值為0CCCCCCCCh,也就是將main函式內的所有值都變成了0CCCCCCCCh,現在的堆疊就成了:
(4).現在開始代碼段
int a = 10;
mov dword ptr [ebp-8],0Ah
int b = 20;
mov dword ptr [ebp-14h],14h
int c = 0;
mov dword ptr [ebp-20h],0
這就是正常的賦值操作,第一條創建a=10,第二條創建b=20,第三條創建c=0;
(5)add函式的呼叫
c = add(a, b);
mov eax,dword ptr [ebp-14h]
push eax
mov ecx,dword ptr [ebp-8]
push ecx
call 00961023
add esp,8
mov dword ptr [ebp-20h],eax
第一條是現將b的值放到eax中,第二條是講a的值放在ecx中,然后將eax,ecx壓堆疊,在執行call指令,將call指令的下一條陳述句地址壓入堆疊頂,然后進入準備呼叫的函式

(6)add函式內部:
int add(int a, int b)
{
009617A0 push ebp
009617A1 mov ebp,esp
009617A3 sub esp,0C0h
009617A9 push ebx
009617AA push esi
009617AB push edi
009617AC mov edi,ebp
009617AE xor ecx,ecx
009617B0 mov eax,0CCCCCCCCh
009617B5 rep stos dword ptr es:[edi]
009617B7 mov ecx,96C003h
009617BC call 0096130C
return a + b;
009617C1 mov eax,dword ptr [ebp+8]
009617C4 add eax,dword ptr [ebp+0Ch]
}
這個和main函式開始的時候一樣都是創建空間,但eax和ecx的值用于add函式的初始化,且在程序中被更改,但壓入堆疊中的"eax"和"ecx"的值并不受影響,因為它們并不是我們所說的eax與ecx,留在堆疊中的只是將a,b賦給eax和ecx后所留下的一個值拷貝,
最后在將結果送到eax暫存器中,通過暫存器帶回函式的回傳值,
(7)add函式的回傳,
前三句是出堆疊,然后將ebp的值賦給esp使得esp下移
倒數第二句從堆疊頂彈出一個元素到ebp中,此時堆疊頂放的正好是main函式的ebp,然后回到main函式的堆疊幀,ret指令會使得出堆疊一次,并將出堆疊的內容作為地址,將程式執行跳轉到該地址
009617C7 pop edi
009617C8 pop esi
009617C9 pop ebx
009617CA add esp,0C0h
009617D0 cmp ebp,esp
009617D2 call 00961235
009617D7 mov esp,ebp
009617D9 pop ebp
009617DA ret
最后列印并輸出
printf("%d", c);
009625BD mov eax,dword ptr [ebp-20h]
009625C0 push eax
009625C1 push 967BCCh
009625C6 call 009613A2
009625CB add esp,8
return 0;
這就是完整的函式堆疊幀創建和銷毀程序,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/295701.html
標籤:其他
上一篇:【LeetCode】一個整型陣列里除兩個數字之外,其他數字都出現了兩次,請找出這兩個只出現一次的數字(劍指 Offer 56 - I. 陣列中數字出現的次數) | 陣列、分組異或
