目錄
準備階段
堆疊頂指標和堆疊底指標
函式堆疊幀的創建與銷毀:
1、大體分析思路(匯編代碼)
2、main函式的創建
具體程序:
畫圖:
3、儲存變數
具體程序
畫圖
3、 ADD函式的創建與銷毀
傳參
ADD函式的創建
變數的創建
ADD函式的銷毀
4、列印c的值
具體程序
畫圖
5、main函式的銷毀
具體程序
畫圖
準備階段
如果想上手操作并看到程序,不建議跳過準備階段部分,仔細閱讀這個部分(直接從暫存器看,也可以),
2019版本 - VS編譯器
用到VS編譯器中的:反匯編視窗、記憶體視窗、監視視窗,
按鍵盤上的F10(逐程序除錯) —— 點擊上方的除錯 —— 視窗 —— 反匯編 —— 記憶體 —— 監視

把反匯編、記憶體、和監視視窗打開后是下面這樣:

接下來按F10來一步一步的除錯,觀察記憶體視窗和監視視窗來分析執行的步驟,
堆疊頂指標和堆疊底指標
暫存器:
有eax,ebx,ecx,edx,今天重點的暫存器是:ebp(堆疊底指標),esp(堆疊頂指標),這兩個暫存器是用來維護函式堆疊幀的,
注意:暫存器是放在cpu中的,不在main函式中
在不同的編譯器下,函式呼叫的程序中堆疊幀的創建是略有差異的,具體的細節取決于編譯器的實作,
在觀察函式堆疊幀的創建與銷毀的程序中有兩個非常重要的指標 esp(堆疊頂指標)和ebp(堆疊底指標),他們兩個是用來維護函式堆疊幀的,觀察時,主要看這兩個指標(esp,ebp),在指標esp上方的記憶體是可以存放資料的記憶體,
函式堆疊幀的創建與銷毀:
1、大體分析思路(匯編代碼)
用一段簡單的代碼分析函式堆疊幀的創建與銷毀

下面的代碼是上面代碼的匯編代碼(更容易觀察堆疊幀創建和銷毀的程序):

ADD函數的創建與銷毀

2、main函式的創建
具體程序:
int main()
{
005518D0 push ebp //壓堆疊:把ebp的放在堆疊的上面,然后esp上移一個整型
005518D1 mov ebp,esp //把ebp的值改成esp的值
005518D3 sub esp,0E4h //把esp的值改成(esp – 0E4h)(0E4h為228)的值
005518D9 push ebx //壓堆疊:把ebx的放在堆疊的上面,然后esp上移一個整型
005518DA push esi //壓堆疊:把esi的放在堆疊的上面,然后esp上移一個整型
005518DB push edi //壓堆疊:把edi的放在堆疊的上面,然后esp上移一個整型
005518DC lea edi,[ebp-24h] //edi中的值變成:ebp-24h
005518DF mov ecx,9 //ecx中的值變成:9
005518E4 mov eax,0CCCCCCCCh //eax中的值變成:0CCCCCCCh
005518E9 rep stos dword ptr es:[edi] //從edi存放的地址到ebp存放的地址全部初始化為0CCCCCCCh
005518EB mov ecx,55C003h //ecx中的值變成:55C003h
005518F0 call 0055131B //
說明:
main函式也是一個函式,既然是函式那么就有函式堆疊幀的創建與銷毀
Push——壓堆疊(給堆疊頂放一個元素)、move——把后一位的值賦予前一位、sub——減去一個數、dword —— 一個整型
畫圖:

3、儲存變數
具體程序
int a = 10;
005518F5 mov dword ptr [ebp-8],0Ah //把ebp-8中的值變成0Ah
int b = 20;
005518FC mov dword ptr [ebp-14h],14h //把ebp-14h中的值變成14h
int c = 0;
00551903 mov dword ptr [ebp-20h],0 //把ebp-20h中的值變成0
c = ADD(a, b);
畫圖

3、 ADD函式的創建與銷毀
傳參
具體程序
c = ADD(a, b);
0055190A mov eax,dword ptr [ebp-14h] //eax中放ebp-14h的值
0055190D push eax //壓堆疊:
0055190E mov ecx,dword ptr [ebp-8] //ecx中放ebp-8的值
00551911 push ecx //壓堆疊:
00551912 call 005513B6 //壓堆疊:放005512B6
畫圖

ADD函式的創建
具體程序
int ADD(int x, int y)
{
00551770 push ebp //壓堆疊:
00551771 mov ebp,esp //把ebp的值改成esp的值
00551773 sub esp,0CCh //把esp的值改成(esp – 0CCh)(0CCh為204)的值
00551779 push ebx //壓堆疊:
0055177A push esi //壓堆疊:
0055177B push edi //壓堆疊:
0055177C lea edi,[ebp-0Ch] //edi中的值變成:ebp-0Ch
0055177F mov ecx,3 //ecx中的值變成:3
00551784 mov eax,0CCCCCCCCh //eax中的值變成:0CCCCCCCh
00551789 rep stos dword ptr es:[edi]//edi存放的地址到ebp存放的地址全部初始化成0CCCCCCCh
0055178B mov ecx,55C003h //ecx中的值變成:55C003h
00551790 call 0055131B //
畫圖
其中的 005513B6 是call指令的下一條地址
變數的創建
具體程序
int z = 0;
00551795 mov dword ptr [ebp-8],0 //為z開辟空間:把ebp-8改成0
z = x + y;
0055179C mov eax,dword ptr [ebp+8] //把ebp+8(形參x)的中的值放在eax中
0055179F add eax,dword ptr [ebp+0Ch]//eax加上ebp+0Ch(形參y)中的值
005517A2 mov dword ptr [ebp-8],eax //把eax(兩個數相加的值)放入ebp-8(z)中
return z;
005517A5 mov eax,dword ptr [ebp-8] //把回傳值(ebp-8)放入eax中
畫圖

ADD函式的銷毀
具體程序
005517A8 pop edi //pop——出堆疊:放出edi
005517A9 pop esi //出堆疊:放出esi
005517AA pop ebx //出堆疊:放出ebx
005517AB add esp,0CCh //esp加上0CCh(16進制)
005517B1 cmp ebp,esp //
005517B3 call 00551244 //
005517B8 mov esp,ebp //esp的值變成ebp
005517BA pop ebp //出堆疊:彈出堆疊頂的ebp(main)
005517BB ret //回到地址005512B6(call指令的下一條指令)
畫圖

4、列印c的值
具體程序
00551917 add esp,8 //esp 加 8
0055191A mov dword ptr [ebp-20h],eax //ebp-20(c)的值改成eax中的值
printf("%d\n", c);
0055191D mov eax,dword ptr [ebp-20h] //eax中的值改成ebp-20h(c)中的值
00551920 push eax //壓堆疊:
00551921 push 557B30h //壓堆疊:
00551926 call 005510CD //進入printf函式(和ADD函式的創建和銷毀一樣)
//這個函式執行的是在螢屏上列印C的值
0055192B add esp,8 //esp加8
畫圖

5、main函式的銷毀
具體程序
return 0;
0055192E xor eax,eax //
}
00551930 pop edi //出堆疊
00551931 pop esi //出堆疊
00551932 pop ebx //出堆疊
00551933 add esp,0E4h //esp加上0E4h(228)
00551939 cmp ebp,esp //
0055193B call 00551244 //
00551940 mov esp,ebp //esp的值改成ebp的值
00551942 pop ebp //出堆疊:把ebp彈出來
00551943 ret //回到call的下一條陳述句
畫圖

謝謝觀看(如有錯誤歡迎指正)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/293219.html
標籤:其他
上一篇:五種高階IO模型以及多路轉接技術(select、poll和epoll)及其代碼驗證
下一篇:光立方原理圖理解
