C程式執行時記憶體結構分析
實驗知識
- 靜態變數儲存在靜態儲存區,區域性變數儲存在動態儲存區(棧),程式碼存放在程式碼區
- 暫存器,EBP指向棧底,ESP指向棧頂,EIP指向正在執行指令的下一條指令,三個暫存器中儲存的都是地址,32位系統,地址為4個位元組即dword
- 所有寫在函式定義裡面的語句都編譯成指令(驅動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; }
這段程式碼包含兩個函式,因此可以測試函式呼叫,此外還包含了靜態變數、區域性變數、返回值等
實驗測試
測試工具:VC6.0
原始碼及對應的彙編如下
暫存器及記憶體狀態如下
EBP棧頂初始值為0018FF84h,ESP初始為0018FF48h
ESP和EBP在棧中的作用
在每個函式最開始的地方有兩條語句
push ebp mov ebp,esp
在函式返回前也有兩條語句
mov esp,ebp pop ebp
每執行一個函式就新開一段棧空間,所謂的開棧空間就是移動ebp棧底,在移動ebp之前,通過push ebp儲存上一級函式的棧底,然後用ebp指向現在函式棧的棧頂,即為當前函式開闢了棧;接著給區域性變數進行地址分配以及儲存現場等,esp不斷向低地址移動,當函式呼叫結束時,esp指回當前函式的棧頂(mov esp,ebp),然後上一級函式的棧頂地址出棧儲存在ebp中(pop ebp)。因此,每一個函式的棧頂上面都儲存著上一級函式的棧頂地址,用於當前函式結束時能夠返回上一級函式的棧,通過ebp和esp以及壓棧出棧操作對棧進行維護。
逐條分析
main函式對應的彙編程式碼如下
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開闢了一段棧空間,留待後面儲存區域性變數,此時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重複儲存在以edi開始的棧空間裡,重複次數為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) // 以上實際上是為形參分配記憶體,順序從右到左,此步進行函式跳轉 00401053 add esp,8 // 形參的地址回收,esp=0018FEE8h+8=0018FEF0h 00401056 mov [_m (00424a30)],eax // 返回值存放在靜態變數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函式的彙編程式碼理解
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函式,ebp壓棧時儲存的地址是0018FF44h,即main函式棧開始開始的地方,然後ebp指向當前函式棧開始的地方 17: int c = 0; 004010A8 mov dword ptr [ebp-4],0 // 為c分配地址,並賦值 18: c = a + b; 004010AF mov eax,dword ptr [ebp+8] // 獲得第一個引數 004010B2 add eax,dword ptr [ebp+0Ch] // 與第二個引數求和 004010B5 mov dword ptr [ebp-4],eax // 結果儲存在c中 19: return c; 004010B8 mov eax,dword ptr [ebp-4] // 返回值存放在eax 20: } 004010BB pop edi // 現場恢復 004010BC pop esi 004010BD pop ebx 004010BE mov esp,ebp // 當前函式棧空間回收,以後可重新分配,esp=0018FEE8h 004010C0 pop ebp // ebp恢復為0018FF44h 004010C1 ret // 返回,等待執行函式呼叫的下一條指令
呼叫fun函式時的記憶體情況
區域性變數i和j儲存在48h空間的開始位置(高地址),即棧底附近,如下圖
在呼叫fun函式之前,將形參從右至左依次壓棧,如下圖
call fun函式時執行跳轉
相關文章
- JVM基本結構、類載入過程以及執行時記憶體溢位分析JVM記憶體溢位
- Hotspot VM 執行時資料區記憶體結構劃分HotSpot記憶體
- 關於C、Java、Python程式執行耗時及記憶體用量JavaPython記憶體
- 程式執行過程記憶體分析詳解記憶體
- Java虛擬機器詳解(二)------執行時記憶體結構Java虛擬機記憶體
- C++ struct結構體記憶體對齊C++Struct結構體記憶體
- c 結構體記憶體對齊詳解結構體記憶體
- Java程式執行記憶體機制Java記憶體
- 記憶體結構記憶體
- 通過 HelloWorld 瞭解 Java 程式執行過程以及執行時記憶體Java記憶體
- Java 執行時的記憶體劃分Java記憶體
- Postgresql資料庫體系結構-程式和記憶體結構SQL資料庫記憶體
- PHP 獲取程式碼執行時間和消耗的記憶體PHP記憶體
- C 語言結構體記憶體佈局問題結構體記憶體
- C語言結構體記憶體佈局問題C語言結構體記憶體
- JVM執行時記憶體資料區域JVM記憶體
- JVM記憶體結構JVM記憶體
- PostgreSQL:記憶體結構SQL記憶體
- 監控 Python 記憶體使用情況和程式碼執行時間!Python記憶體
- MySQL查詢select語句的執行流程以及InnoDB記憶體結構MySql記憶體
- 結構體記憶體對齊結構體記憶體
- Java記憶體區域(執行時資料區域)和記憶體模型(JMM)Java記憶體模型
- 獲取 Laravel 執行時間和記憶體消耗Laravel記憶體
- Java 執行時資料區和記憶體模型Java記憶體模型
- C程式記憶體佈局C程式記憶體
- Java記憶體區域與記憶體溢位異常 - 執行時資料區Java記憶體溢位
- 分析oc物件的記憶體結構及其建立過程物件記憶體
- C結構體中資料的記憶體對齊問題結構體記憶體
- C/C++使用malloc為結構體陣列分配記憶體(及free釋放記憶體)的三種方法C++結構體陣列記憶體
- MySQL整體架構與記憶體結構MySql架構記憶體
- Java 執行緒記憶體模型Java執行緒記憶體模型
- 設定SQLserver執行記憶體SQLServer記憶體
- 理解JVM(一):記憶體結構JVM記憶體
- JVM(七):JVM記憶體結構JVM記憶體
- JVM記憶體結構劃分JVM記憶體
- JVM記憶體結構、Java記憶體模型和Java物件模型JVM記憶體Java模型物件
- 圖解JVM記憶體模型及JAVA程式執行原理圖解JVM記憶體模型Java
- Linux上執行記憶體中的指令碼和程式Linux記憶體指令碼
- mimalloc記憶體分配程式碼分析記憶體