




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第C語言超詳細解析函數棧幀目錄一、前面二、預備知識三、棧幀創建與銷毀四、總結
一、前面
本章將以匯編視角看函數棧幀的內存是如何使用與回收的,為了降低匯編語言的理解成本,以圖示的方式講解每一步匯編指令所帶來的效果,來逐步展示函數棧幀的形成與銷毀的整個過程。
展示環境:win10vs2025
二、預備知識
這些預備知識理解與否對本篇文章并無很大關系,之所以預備這些知識是為了讓讀者能夠更加相信函數棧幀的形成與銷毀過程就是如此。
棧區:內存四區之一,內存為了使用和管理,被劃分為四部分,其中棧區就是內存被劃分的區域之一,棧的使用習慣是,先使用高地址部分,在使用底地址部分。
函數棧幀:即在調用函數時,為函數開辟的一塊內存空間,由于該內存空間在棧區,因此該空間被稱作函數棧幀,簡稱棧幀。
棧頂:故名思意,就是棧的頂部,更確切的說是指向存放在棧區數據的頂部。
棧底:棧的底部。
寄存器:寄存器cpu內部用來存放數據的一些小型存儲區域,用來暫時存放參與運算的數據和運算結果。簡單來說就是獨立于內存,用來存儲少量數據的器件。
ebp:棧底指針寄存器
esp:棧底指針寄存器
其它寄存器:ebx、esi、edi、ecx、eax
入棧(壓棧):先將棧頂指針向上移動四字節的大小空間,再將寄存器的數據放入那四字節空間。這里的向上移動是指向低地址處移動。
入棧指令:pusha。
圖解:以pusha為例。
出棧:將棧頂指針向下移動四字節,這里的向下是往低地址處移動四個字節的空間。并將這四個字節的數據放入某個寄存器中。
出棧指令:popa。
圖解:以popa為例。
簡單匯編操作指令
movab:將b賦值給a,c語言表示就是a=b。
subab:將a-b的結果賦值給a,c語言表述就是a=a-b。
addab:將a+b的結果賦值給a,c語言表述就是a=a+b。
由于理解成本的原因,遇到的其它匯編指令本文會直接指出它的作用效果。
三、棧幀創建與銷毀
以Add函數調用為例
#define_CRT_SECURE_NO_WARNINGS1
#includestdio.h
intAdd(intx,inty)
intz=x+y;
returnz;
intmain()
inta=10;
intb=20;
intz=0;
z=Add(a,b);
printf("%d\n",z);
return0;
}
該代碼對應的匯編指令如下:
需要說明的是,main函數也被別的函數調用的,調用關系是:__mainCRTStartup調用main函數,mainCRTStartup函數調用__mainCRTStartup。
再調用main函數之前,棧區是這樣的。
指令分說:
intmain()
00F71E40pushebp
00F71E41movebp,esp
00F71E43subesp,0E4h
以上圖為參照。
第一條指令:將寄存器ebp的值壓棧
第二條指令:將寄存器esp的值賦值給ebp
第三條指令:將esp-0E4h賦值給寄存器esp,形象的表述是esp向低地址方向移動4個字節,上端為低地址,下端為高地址,即向上移動4字節空間。
棧區視圖變為:
這三條指令,簡單來說就是為main函數在棧區開辟了一塊空間(這塊空間大小系統會幫我們自動開辟好。)
指令分說:
00F71E49pushebx
00F71E4Apushesi
00F71E4Bpushedi
將三個寄存器的值壓入棧中
棧區視圖變為:
指令分說:
00F71E4Cleaedi,[ebp-24h]
00F71E4Fmovecx,9
00F71E54moveax,0CCCCCCCCh
00F71E59repstosdwordptres:[edi]
這四條指令我們就解讀了,效果就是將main函數的棧幀空間以16進制值cccccccc填充。
棧區視圖變為:
指令分說:
00F71E5Bmovecx,0F7C003h
00F71E60call00F7130C
這兩條指令是編譯器檢查用的,初學不必花費更多時間了解更細節的部分。
vs2013沒有這一檢查部分,vs2025檢查很嚴格。
指令分說:
inta=10;
00F71E65movdwordptr[ebp-8],0Ah
intb=20;
00F71E6Cmovdwordptr[ebp-14h],14h
intz=0;
00F71E73movdwordptr[ebp-20h],0
第一條匯編指令:將0Ah放入[ebp-8]這塊空間中,即把a放入那塊空間。
第二條匯編指令:將14h放入[ebp-14h]這塊空間中,即把b放入那塊空間中。
第三條匯編指令:將0放入[ebp-20h]這塊空間中。即把z放入那塊空間中。
棧區圖示:
簡單來說:就是將局部變量放入對應的函數棧幀中。
指令分說:
z=Add(a,b);
00F71E7Amoveax,dwordptr[ebp-14h]
00F71E7Dpusheax
00F71E7Emovecx,dwordptr[ebp-8]
00F71E81pushecx
第一條指令:將【ebp-20】這塊空間4字節的數據放入eax中。即把b=20的數據放入eax中。
第二條指令:將eax的數據壓棧。
第三條指令:將【ebp-8】這塊空間4字節的數據放入ecx中。即把a=10的數據放入ecx中。
第四條指令:將ecx的數據壓棧。
棧區視圖:
這里的20和10,就是我們傳過去的實參,之后Add函數調用的x和y就是指這兩塊空間。
那么我們可以知道:函數傳參是從右向左傳的。這里就是先傳的b再傳的a。
指令分說:
00F71E82call00F710B4
調用的函數:
intAdd(intx,inty)
{
00F71740pushebp
00F71741movebp,esp
00F71743subesp,0CCh
00F71749pushebx
00F7174Apushesi
00F7174Bpushedi
00F7174Cleaedi,[ebp-0Ch]
00F7174Fmovecx,3
00F71754moveax,0CCCCCCCCh
00F71759repstosdwordptres:[edi]
00F7175Bmovecx,0F7C003h
00F71760call00F7130C
intz=x+y;
00F71765moveax,dwordptr[ebp+8]
00F71768addeax,dwordptr[ebp+0Ch]
00F7176Bmovdwordptr[ebp-8],eax
returnz;
00F7176Emoveax,dwordptr[ebp-8]
}
00F71771popedi
00F71772popesi
00F71773popebx
00F71774addesp,0CCh
00F7177Acmpebp,esp
00F7177Ccall00F71235
00F71781movesp,ebp
00F71783popebp
00F71784ret
第一條匯編指令:call是調用指令,調用Add函數。
經過上次的指令,這里我就直接介紹效果了。
00F71740pushebp
00F71741movebp,esp
00F71743subesp,0CCh
這三條指令,為Add函數在棧區開辟對應的空間大小。
棧區圖示:
00F71749pushebx
00F7174Apushesi
00F7174Bpushedi
將ebx,esi,edi入棧。
圖示:
00F7174Cleaedi,[ebp-0Ch]
00F7174Fmovecx,3
00F71754moveax,0CCCCCCCCh
00F71759repstosdwordptres:[edi]
對Add函數棧幀做初始化,將里面的數據置換為cccccccc。(用于初始化棧幀的具體數值取決于編譯器)
00F7175Bmovecx,0F7C003h
00F71760call00F7130C
編譯器做的檢查,不必理會。
intz=x+y;
00F71765moveax,dwordptr[ebp+8]
00F71768addeax,dwordptr[ebp+0Ch]
00F7176Bmovdwordptr[ebp-8],eax
取[ebp+8]空間的數據放入eax中
取[ebp+0Ch]與eax的數據相加后放入eax中。
將eax的值放入ptr[ebp-8]中。
圖示:
returnz;
00F7176Emoveax,dwordptr[ebp-8]
返回時,通過寄存器的方式,將返回值交給寄存器。
00F71771popedi
00F71772popesi
00F71773popebx
00F71774addesp,0CCh
00F7177Acmpebp,esp
00F7177Ccall00F71235
00F71781movesp,ebp
00F71783popebp
00F71784ret
代碼分說:
00F71771popedi
00F71772popesi
00F71773popebx
將edi、esi、ebx出棧
圖示:
00F71774addesp,0CCh
00F7177Acmpebp,esp
00F7177Ccall00F71235
00F71781movesp,ebp
00F71783popebp
0CCh是Add函數棧幀的大小
所以esp向下移動到dbp的位置。
之后popebp,由于棧頂指向的是main函數棧幀的棧底,因此出棧ebp指向main函數棧幀的棧底。
圖示:
調用Add返回之后,繼續執行以下指令。
00A717F7addesp,8
00A717FAmovdwordptr[ebp-20h],eax
return0;
00A717FDxoreax,eax
}
00A717FFpopedi
00A71800popesi
00A71801popebx
00A71802addesp,0E4h
00A71808cmpebp,esp
00A7180Acall00A71235
00A7180Fmovesp,ebp
00A71811popebp
00A71812ret
第一條指令:將esp向下移動8個字節,即銷毀x和y這兩塊連續的形參。
第二條指令:將寄存器eax保存的Add函數的返回值交給z。
圖示:
之后的指令就是回收main函數的棧幀了,回收過程都差不多,就不細細講解了。
四、總結
以下函數調用為例。
#define_CRT_SECURE_NO_WARNINGS1
#includestdio.h
intAdd(intx,inty)
intz=x+y;
returnz;
intmain()
inta=10;
intb=20;
intz=0;
z=Add(a,b);
return0;
}
初始:mainCRTStartup函數調用__mainCRTStartup、__mainCRTStartup調用main函數。
棧區上先為以上兩個函數分配函數棧幀。
調用main函數時,為main函數分配函數棧幀(該大小是自動開辟
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- ××超市某超市員工招聘制度
- 網絡安全保障協議和責任界定
- 汽車行業購車資格及經濟實力出資證明書(6篇)
- 2025年自動造型線項目申請報告
- 法律邏輯學案例分析與解析手冊
- 2025年橋架項目提案報告
- 冬日雪景抒寫作文9篇
- 2025年保密局公務員錄用考試申論試卷
- 建筑設計優化服務協議
- 2025年大學輔導員招聘考試:學生社團管理案例分析歷年真題解析匯編
- 2025年黑龍江省龍東地區中考數學試卷真題(含答案)
- 2025年中小學暑假安全教育主題家長會 課件
- 顱內血腫護理查房
- 門診急救室管理制度
- 2025年沈陽水務集團有限公司-企業報告(代理機構版)
- 近視管理白皮書(2025)專家共識-
- 2024年深圳市深汕特別合作區農村工作者招聘真題
- 數字化藝術-終結性考核-國開(SC)-參考資料
- 2024年貴州省糧食儲備集團有限公司招聘考試真題
- 2025山西晉城市國有資本投資運營有限公司部分子公司招聘11人筆試參考題庫附帶答案詳解
- 2025盤錦市興隆臺區輔警考試試卷真題
評論
0/150
提交評論