<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們知道,每一次函數呼叫都需要在棧區上為其開闢一塊空間,這塊空間就叫做這個函數的棧幀。
而棧是從高地址向低地址延伸的。每個函數的每次呼叫,都有它自己獨立的一個棧幀,這個棧幀中維持著所需要的各種資訊。暫存器ebp指向當前的棧幀的底部(高地址),暫存器esp指向當前的棧幀的頂部(低地址)。
這樣我們就瞭解了暫存器ebp和暫存器esp中存放的是地址,這兩個地址是用來維護函數棧幀的。比如:呼叫main函數, 我們為main函數分配棧幀空間, 那麼棧幀維護如下:
下面我們通過一段程式碼分析一下,函數棧幀建立和銷燬的過程:(棧幀這部分內容在不同的編譯器上實現存在差異, 但是思想大致都是一致的。本文是在vs2013編譯器下實現的。)
#include <stdio.h> int Add(int x, int y) { int z = 0; z = x + y; return z; } int main(void) { int a = 10; int b = 20; int ret = 0; ret = Add(a, b);//計算a+b printf("%dn", ret); return 0; }
我們在偵錯過程開啟呼叫堆疊
可以看出,main函數是在__tmainCRTStartup函數內部被呼叫的,而__tmainCRTStartup函數又是在mainCRTStartup函數內部呼叫的。
為了能更加清楚的看到棧幀建立和銷燬的過程,我們轉到上面程式碼對應的反組合程式碼:
int main(void) { 009D3F40 push ebp //將edp壓入棧幀 009D3F41 mov ebp,esp //將esp的值賦給edp 009D3F43 sub esp,0E4h //esp-0E4h 009D3F49 push ebx 009D3F4A push esi 009D3F4B push edi 009D3F4C lea edi,[ebp+FFFFFF1Ch] 009D3F52 mov ecx,39h 009D3F57 mov eax,0CCCCCCCCh 009D3F5C rep stos dword ptr es:[edi] int a = 10; 009D3F5E mov dword ptr [ebp-8],0Ah int b = 20; 009D3F65 mov dword ptr [ebp-14h],14h int ret = 0; 009D3F6C mov dword ptr [ebp-20h],0 ret = Add(a, b);//計算a+b 009D3F73 mov eax,dword ptr [ebp-14h] 009D3F76 push eax 009D3F77 mov ecx,dword ptr [ebp-8] 009D3F7A push ecx 009D3F7B call 009D11F9 009D3F80 add esp,8 009D3F83 mov dword ptr [ebp-20h],eax printf("%dn", ret); 009D3F86 mov esi,esp 009D3F88 mov eax,dword ptr [ebp-20h] 009D3F8B push eax 009D3F8C push 9D5860h 009D3F91 call dword ptr ds:[009D9118h] 009D3F97 add esp,8 009D3F9A cmp esi,esp 009D3F9C call 009D1140 return 0; 009D3FA1 xor eax,eax } 009D3FA3 pop edi 009D3FA4 pop esi 009D3FA5 pop ebx 009D3FA6 add esp,0E4h 009D3FAC cmp ebp,esp 009D3FAE call 009D1140 009D3FB3 mov esp,ebp 009D3FB5 pop ebp 009D3FB6 ret
main函數的呼叫 main函數棧幀的建立
經過剛才我們的理解,在準備呼叫main函數的時候,呼叫main函數的那個函數的棧幀已經開闢好了。
然後將ebp壓入棧幀,儲存了指向棧底的ebp的地址,而此時esp指向新的棧頂位置;接著將esp的值賦給了ebp,產生了新的ebp;用esp減去一個16進位制數0E4H(這裡就是為main函數預開闢空間)。緊接著三個壓棧指令,分別將ebx,esi,edi,壓入棧幀。載入完有效地址以後,將為main函數預開闢空間全部初始化為0xCCCCCCCC。最後建立了三個區域性變數a,b,ret並進行了初始化。
將b的值存入暫存器eax中,再將eax壓入棧中;將a的值存入暫存器ecx中,再將將ecx壓入棧中;這裡看出引數是從右向左傳遞的。緊接著執行call指令,這裡就是呼叫Add函數,同時將call指令的下一條指令的地址壓入棧中,然後執行call指令的時候按F11 , 就進入了Add函數內部。
首先將main()函數的ebp壓入棧,儲存指向main()函數棧幀底部的ebp的地址,此時esp指向新的棧頂位置;將esp的值賦給ebp,產生新的ebp,即Add()函數棧幀的ebp;給esp減去一個16進位制數0E4H,這裡是為Add()函數預開闢空間;緊接著三個壓棧指令,分別將ebx,esi,edi,壓入棧幀。載入完有效地址以後,將為Add函數預開闢空間全部初始化0xCCCCCCCC。在緊接著建立了變數z,將形參的a和b相加的結果儲存到z中;最後將結果儲存到eax暫存器中,通過暫存器帶回了函數的返回值。
edi、esi、ebx依次出棧,esp 會向下移動;然後將ebp的值賦給esp,使esp指向ebp指向的地方;接著ebp 出棧,同時將出棧的內容給ebp,此時ebp又指向了main函數棧幀的底部,最後執行ret 指令,表示出棧一次,並跳轉到出棧的內容的地址處,也就是call指令的下一條指令處。
main函數棧幀的銷燬和Add函數棧幀銷燬的過程的思想都是一樣的,這裡就不做多贅述了。
通過上面的例子,我們知道了區域性變數是如何建立的,知道了為什麼建立區域性變數不初始化,會導致裡面的內容是隨機值;對函數是如何傳參的,以及傳參順序是如何也有了較為深入的瞭解。
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45