日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C語言函數棧幀的創建與銷毀原理圖解_C 語言

作者:頭發沒有代碼多 ? 更新時間: 2022-07-15 編程語言

什么是函數棧幀

我們在寫C語言代碼的時候,經常會把一個獨立的功能抽象為函數,所以C程序是以函數為基本單位的。

那函數是如何調用的?函數的返回值又是如何待會的?函數參數是如何傳遞的?這些問題都和函數棧幀有關系。

函數棧幀(stack frame)就是函數調用過程中在程序的調用棧(call stack)所開辟的空間,這些空間是用來存放:

  • 函數參數和函數返回值
  • 臨時變量(包括函數的非靜態的局部變量以及編譯器自動生產的其他臨時變量)
  • 保存上下文信息(包括在函數調用前后需要保持不變的寄存器)。

什么是棧?

棧(stack)是現代計算機程序里最為重要的概念之一,幾乎每一個程序都使用了棧,沒有棧就沒有函 數,沒有局部變量,也就沒有我們如今看到的所有的計算機語言。

與函數棧幀有關的匯編語句

eax:通用寄存器,保留臨時數據,常用于返回值

ebx:通用寄存器,保留臨時數據

ebp:棧底寄存器

esp:棧頂寄存器

eip:指令寄存器,保存當前指令的下一條指令的地址

mov:數據轉移指令

push:數據入棧,同時esp棧頂寄存器也要發生改變

pop:數據彈出至指定位置,同時esp棧頂寄存器也要發生改變

sub:減法命令

add:加法命令

call:函數調用,1. 壓入返回地址 2. 轉入目標函數

jump:通過修改eip,轉入目標函數,進行調用

ret:恢復返回地址,壓入eip,類似pop eip命令(返回子程序)

函數如何創建棧幀并銷毀

當程序進入main函數時,要給main函數在棧區創建空間,esp(棧頂)和ebp(棧底)對main函數進行維護

當程序執行時,我們在調試窗口對堆棧段進行調用,我們可以看到main函數是被__tmainSRTStartup函數所調用,說明main函數是它的內部函數,而__tmainSRTStartup又是被mainCRStartup這個函數調用

梳理一下上面的思路

這些函數在堆棧當中的存儲

main函數棧幀開辟

接下來重新調試,我們轉到反匯編

調用main函數之前,esp和ebp對調用main函數的函數進行維護 ,當棧頂發生改變時,esp會指向新的棧頂

003118B0 push ebp

003118B1 mov ebp,esp

先把ebp入棧,然后把ebp移動到esp的位置

003118B3 sub esp,0E4h

003118B9 push ebx

003118BA push esi

003118BB push edi

之后又把esp往上移動,移動完把ebx,esi,edi壓棧,esp和ebp現在指的這塊空間是為main函數預先開辟好的

把edi-0EFH也就是main函數開始的這里的地址,放到edi里面去,然后從這個地址開始賦值39次的雙字節數據,賦值為CCCC

到這里main函數棧幀開辟完成

接下來就是在main函數的空間里,創建三個變量,并給賦值

調用Add函數

對函數進行傳參,創建倆個臨時變量,然后壓棧進去

接下來進入call開始調用函數call此時的地址是00C2144B

此時按下F11,我們發現call指令的下一條地址被壓到了棧區

把call的下一個地址壓棧,ps:后面會用到這條指令,可先放在這不管

接下來進入Add函數,跟前面main函數一樣,先開辟空間,然后賦值為CCCCCC,再為變量在函數里創建空間并賦值

接下來執行加法運算,由于剛才已經創建好了零時變量,所以把他倆進行相加,加完之后把結果傳過來就行,傳過來之后把這個值放在eax里面去

返回主函數

按順序出棧,之后把ebp賦值給esp

之后pop,ebp把ebp進行出棧,ebp便回到main函數這里,ebp此時回到這里,esp也自然而然的往下指一個,ret指令是返回,然后esp來到了call指令的下一條指令

把棧頂指針彈出去,esp自然向下指一條

之后給esp加8即釋放這倆個臨時變量

之后把eax放到ebp-20h,eax是存放剛才加法和的地方

原文鏈接:https://blog.csdn.net/weixin_49449676/article/details/124508436

欄目分類
最近更新