中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

C程序運行時內(nèi)存結(jié)構(gòu)分析

2018-07-20    來源:編程學習網(wǎng)

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

實驗知識

  • 靜態(tài)變量存儲在靜態(tài)存儲區(qū),局部變量存儲在動態(tài)存儲區(qū)(棧),代碼存放在代碼區(qū)
  • 寄存器,EBP指向棧底,ESP指向棧頂,EIP指向正在執(zhí)行指令的下一條指令,三個寄存器中保存的都是地址,32位系統(tǒng),地址為4個字節(jié)即dword
  • 所有寫在函數(shù)定義里面的語句都編譯成指令(驅(qū)動CPU)

實驗代碼

#include <stdio.h>
int fun(int a, int b);
int m = 10;
int main()
{
    int i = 4;
    int j = 5;
    m = fun(i, j);
}
int fun(int a, int b)
{
    int c = 0;
    c = a + b;
    return c;
}

這段代碼包含兩個函數(shù),因此可以測試函數(shù)調(diào)用,此外還包含了靜態(tài)變量、局部變量、返回值等

實驗測試

測試工具:VC6.0

源代碼及對應(yīng)的匯編如下

寄存器及內(nèi)存狀態(tài)如下

EBP棧頂初始值為0018FF84h,ESP初始為0018FF48h

ESP和EBP在棧中的作用

在每個函數(shù)最開始的地方有兩條語句

push ebp
mov  ebp,esp

在函數(shù)返回前也有兩條語句

mov esp,ebp
pop ebp

每運行一個函數(shù)就新開一段?臻g,所謂的開?臻g就是移動ebp棧底,在移動ebp之前,通過push ebp保存上一級函數(shù)的棧底,然后用ebp指向現(xiàn)在函數(shù)棧的棧頂,即為當前函數(shù)開辟了棧;接著給局部變量進行地址分配以及保存現(xiàn)場等,esp不斷向低地址移動,當函數(shù)調(diào)用結(jié)束時,esp指回當前函數(shù)的棧頂(mov esp,ebp),然后上一級函數(shù)的棧頂?shù)刂烦鰲14嬖趀bp中(pop ebp)。因此,每一個函數(shù)的棧頂上面都保存著上一級函數(shù)的棧頂?shù)刂,用于當前函?shù)結(jié)束時能夠返回上一級函數(shù)的棧,通過ebp和esp以及壓棧出棧操作對棧進行維護。

逐條分析

main函數(shù)對應(yīng)的匯編代碼如下

7:    int main()
8:    {
00401020   push        ebp                        // ebp初始為0018FF84h壓棧,壓棧后esp = 0018FF48h - 4 = 0018FF44h
00401021   mov         ebp,esp                    // ebp保存棧頂0,ebp=esp=0018FF44h
00401023   sub         esp,48h                    // esp -= 48h開辟了一段?臻g,留待后面保存局部變量,此時esp=0018FF44h-48h=0018FEFCh
00401026   push        ebx                        
00401027   push        esi
00401028   push        edi                        // ebx、esi和edi壓棧,esp = 0018FEFCh - 4*3 = 0018FEF0h
00401029   lea         edi,[ebp-48h]              // lea指令將ebp-48h作為偏移地址保存在edi中,edi=0018FEFCh,即棧中ebx的上面
0040102C   mov         ecx,12h                    
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]            // 將eax重復(fù)保存在以edi開始的?臻g里,重復(fù)次數(shù)為ecx次,向高地址方向,共覆蓋12h*4=48h個地址,即棧中保存ebx的地址以上到ebp指向的地址這一段全部填充為cch
9:        int i = 4;
00401038   mov         dword ptr [ebp-4],4        // 保存變量i
10:       int j = 5;
0040103F   mov         dword ptr [ebp-8],5        // 保存變量j
11:       m = fun(i, j);
00401046   mov         eax,dword ptr [ebp-8]      // 將j保存在eax中
00401049   push        eax                        // eax壓棧, esp=0018FEF0h-4=0018FEECh
0040104A   mov         ecx,dword ptr [ebp-4]      // 將i保存在ecx中
0040104D   push        ecx                        // ecx壓棧,esp=0018FEECh-4=0018FEE8h
0040104E   call        @ILT+0(_fun) (00401005)    // 以上實際上是為形參分配內(nèi)存,順序從右到左,此步進行函數(shù)跳轉(zhuǎn)
00401053   add         esp,8                      // 形參的地址回收,esp=0018FEE8h+8=0018FEF0h
00401056   mov         [_m (00424a30)],eax        // 返回值存放在靜態(tài)變量m中
12:       return 0;
0040105B   xor         eax,eax                    // 返回值置為0
13:   }
0040105D   pop         edi
0040105E   pop         esi
0040105F   pop         ebx
00401060   add         esp,48h
00401063   cmp         ebp,esp
00401065   call        __chkesp (004010d0)
0040106A   mov         esp,ebp
0040106C   pop         ebp
0040106D   ret

fun函數(shù)的匯編代碼理解

15:   int fun(int a, int b)
16:   {
00401090   push        ebp
00401091   mov         ebp,esp
00401093   sub         esp,44h
00401096   push        ebx
00401097   push        esi
00401098   push        edi
00401099   lea         edi,[ebp-44h]
0040109C   mov         ecx,11h
004010A1   mov         eax,0CCCCCCCCh
004010A6   rep stos    dword ptr [edi]            // 以上理解同main函數(shù),ebp壓棧時保存的地址是0018FF44h,即main函數(shù)棧開始開始的地方,然后ebp指向當前函數(shù)棧開始的地方
17:       int c = 0;
004010A8   mov         dword ptr [ebp-4],0        // 為c分配地址,并賦值
18:       c = a + b;
004010AF   mov         eax,dword ptr [ebp+8]      // 獲得第一個參數(shù)
004010B2   add         eax,dword ptr [ebp+0Ch]    // 與第二個參數(shù)求和
004010B5   mov         dword ptr [ebp-4],eax      // 結(jié)果保存在c中
19:       return c;
004010B8   mov         eax,dword ptr [ebp-4]      // 返回值存放在eax
20:   }
004010BB   pop         edi                        // 現(xiàn)場恢復(fù)
004010BC   pop         esi
004010BD   pop         ebx
004010BE   mov         esp,ebp                    // 當前函數(shù)?臻g回收,以后可重新分配,esp=0018FEE8h
004010C0   pop         ebp                        // ebp恢復(fù)為0018FF44h
004010C1   ret                                    // 返回,等待執(zhí)行函數(shù)調(diào)用的下一條指令

調(diào)用fun函數(shù)時的內(nèi)存情況

局部變量i和j保存在48h空間的開始位置(高地址),即棧底附近,如下圖

在調(diào)用fun函數(shù)之前,將形參從右至左依次壓棧,如下圖

call fun函數(shù)時執(zhí)行跳轉(zhuǎn)

標簽: 代碼

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:八款A(yù)ndroid 開發(fā)者必備的小工具

下一篇:減少C++代碼編譯時間的方法