最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言超詳細(xì)講解函數(shù)棧幀的創(chuàng)建和銷毀

 更新時(shí)間:2022年05月05日 15:37:29   作者:野豬佩奇`  
我們知道c語言中函數(shù)都是被調(diào)用的,main函數(shù)里面能調(diào)用其他函數(shù),其實(shí)main函數(shù)也是被別的函數(shù)調(diào)用的,下面通過本文給大家分享c語言函數(shù)棧幀的創(chuàng)建和銷毀過程,一起看看吧

1、本節(jié)目標(biāo)

C語言絕命七連問,你能回答出幾個(gè)?

  • 局部變量是如何創(chuàng)建的?
  • 為什么局部變量不初始化其內(nèi)容是隨機(jī)的?
  • 有些時(shí)候屏幕上輸出的"燙燙燙"是怎么來的?
  • 函數(shù)調(diào)用時(shí)參數(shù)時(shí)如何傳遞的?傳參的順序是怎樣的?
  • 函數(shù)的形參和實(shí)參的關(guān)系是什么?
  • 函數(shù)的返回值是如何帶回的?
  • 函數(shù)是怎樣在棧區(qū)上開辟和釋放空間的?

想要對(duì)上面的這六個(gè)問題做出準(zhǔn)確深入的回答,我們需要學(xué)習(xí)函數(shù)棧幀的創(chuàng)建和銷毀相關(guān)知識(shí),在正式進(jìn)入函數(shù)棧幀之前,我們還需要了解一些相關(guān)的寄存器和匯編指令。

2、相關(guān)寄存器

  • eax:通用寄存器,保留臨時(shí)數(shù)據(jù),常用于返回值。
  • ebx:通用寄存器,保留臨時(shí)數(shù)據(jù)。
  • ebp:棧底寄存器,用來記錄棧底的地址。
  • esp:棧頂寄存器,用來記錄棧頂?shù)牡刂贰?/li>
  • eip:指令寄存器,保存當(dāng)前指令的下一條指令的地址。

3、相關(guān)匯編指令

  • mov:數(shù)據(jù)轉(zhuǎn)移指令。
  • sub:減法命令。
  • add:加法命令。
  • push:數(shù)據(jù)入棧,同時(shí)esp棧頂寄存器也要發(fā)生改變。
  • pop:數(shù)據(jù)彈出至指定位置,同時(shí)esp棧頂寄存器也要發(fā)生改變。
  • call:函數(shù)調(diào)用,1. 壓入返回地址 2. 轉(zhuǎn)入目標(biāo)函數(shù)。
  • jump:通過修改eip,轉(zhuǎn)入目標(biāo)函數(shù),進(jìn)行調(diào)用。
  • lea:傳遞地址指令,用于加載有效地址。
  • ret:恢復(fù)返回地址,壓入eip,類似pop eip命令。

4、什么是函數(shù)棧幀

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

  • 函數(shù)參數(shù)和函數(shù)返回值。
  • 臨時(shí)變量(包括函數(shù)的非靜態(tài)的局部變量以及編譯器自動(dòng)生產(chǎn)的其他臨時(shí)變量)。
  • 保存上下文信息(包括在函數(shù)調(diào)用前后需要保持不變的寄存器)。

同時(shí),每一次函數(shù)調(diào)用,編譯器都會(huì)為該函數(shù)分配一塊空間,而這塊空間就被稱為這個(gè)函數(shù)的函數(shù)棧幀;并且,這塊空間是由兩個(gè)寄存器來維護(hù)的:esp寄存器(記錄棧頂?shù)牡刂罚┖蚭bp寄存器(記錄棧底的地址)。

5、什么是調(diào)用堆棧

函數(shù)調(diào)用堆棧是反饋函數(shù)調(diào)用邏輯的。我們以main函數(shù)的調(diào)用為例:

我們可以看到,mainCRTStartup調(diào)用__scrt_common_main,__scrt_common_main調(diào)用__scrt_common_main_seh,__scrt_common_main_seh調(diào)用_SCRT_STARTUP_MAIN,_SCRT_STARTUP_MAINmain,main調(diào)用Add。

6、函數(shù)棧幀的創(chuàng)建和銷毀

我們以一段程序?yàn)槔v解函數(shù)棧幀:(注意: 函數(shù)棧幀的創(chuàng)建和銷毀過程,在不同的編譯器上實(shí)現(xiàn)的方法和細(xì)節(jié)會(huì)有所差異,一般來說,越新的編譯器對(duì)函數(shù)棧幀的封裝就越嚴(yán)密,本次演示以VS2019為例。)

演示代碼

#include<stdio.h>
int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}
int main()
{
	int a = 3;
	int b = 5;
	int ret = 0;
	ret = Add(a, b);
	printf("%d", ret);
	return 0;
}

(1)、main函數(shù)棧幀的創(chuàng)建與初始化

(2)、main函數(shù)的核心代碼

(3)、Add函數(shù)的調(diào)用過程

F11進(jìn)入Add函數(shù)內(nèi)部,觀察Add函數(shù)的反匯編代碼

代碼執(zhí)行到Add函數(shù)的時(shí)候,就要開始創(chuàng)建Add函數(shù)的棧幀空間了。

在Add函數(shù)中創(chuàng)建棧幀的方法和在main函數(shù)中是相似的,在棧幀空間的大小上略有差異而已。

1. 將main函數(shù)的 ebp 壓棧。

2. 計(jì)算新的 ebp 和 esp。

3. 將 ebx , esi , edi 寄存器的值保存。

4. 計(jì)算求和,在計(jì)算求和的時(shí)候,我們是通過 ebp 中的地址進(jìn)行偏移訪問 到了函數(shù)調(diào)用前壓棧進(jìn)去的參數(shù),這就是形參訪問。

5. 將求出的和放在 eax 寄存器中準(zhǔn)備帶回。

(4)、Add函數(shù)棧幀的銷毀

當(dāng)函數(shù)調(diào)用要結(jié)束返回的時(shí)候,前面創(chuàng)建的函數(shù)棧幀也開始銷毀,具體銷毀過程如下:

(5)、調(diào)用完成

調(diào)用完Add函數(shù),回到main函數(shù)的時(shí)候,繼續(xù)往下執(zhí)行,可以看到:

00BE185D add esp,8 esp直接+8,相當(dāng)于跳過了main函數(shù)中壓棧的a’和b’。

00BE1860 mov dword ptr [ebp-20h],eax 將eax中值,存檔到ebp-0x20的地址處,其實(shí)就是存儲(chǔ)到main函數(shù)中ret變量中,而此時(shí)eax中就是Add函數(shù)中計(jì)算的x和y的和,可以看出來,本次函數(shù)的返回值是由eax寄存器帶回來的。程序是在函數(shù)調(diào)用返回之后,在eax中去讀取返回值的。

7、對(duì)開篇問題的解答

當(dāng)我們完整的了解了函數(shù)棧幀創(chuàng)建和銷毀的過程后,我們就可以回答開篇提到的問題了:

1.局部變量是如何創(chuàng)建的?

局部變量的創(chuàng)建是在局部變量所在的函數(shù)的棧幀創(chuàng)建完成并初始化后,然后在該棧幀內(nèi)為局部變量分配空間的。

2.為什么局部變量不初始化其內(nèi)容是隨機(jī)的?

因?yàn)榫幾g器在創(chuàng)建函數(shù)棧幀后會(huì)在棧幀空間里面放入一個(gè)值,而這個(gè)值是隨機(jī)的。

3.有些時(shí)候屏幕上輸出的"燙燙燙"是怎么來的?

因?yàn)閙ain函數(shù)調(diào)用時(shí),在棧區(qū)開辟的空間的其中每一個(gè)字節(jié)都被初始化為0xCC,而如果我們定義的是一個(gè)未初始化的數(shù)組,且這個(gè)數(shù)組恰好在這塊空間上創(chuàng)建,因?yàn)?xCCCC(兩個(gè)連續(xù)排列的0xCC)的漢字編碼是“燙”,所以屏幕上輸出的就是燙燙燙。

4.函數(shù)調(diào)用時(shí)參數(shù)時(shí)如何傳遞的?傳參的順序是怎樣的?

我們?cè)谡{(diào)用函數(shù)之前,就會(huì)在棧頂上從右向左依次壓入需要傳遞的參數(shù),在創(chuàng)建好被調(diào)函數(shù)的函數(shù)棧幀后通過指針的偏移量來使用傳遞過去的參數(shù),而不是在被調(diào)函數(shù)的函數(shù)棧幀內(nèi)創(chuàng)建形參。

5.函數(shù)的形參和實(shí)參的關(guān)系是什么?

形參是實(shí)參的一份臨時(shí)拷貝,二者的存儲(chǔ)位置不同,形參的改變不會(huì)影響實(shí)參。

6.函數(shù)的返回值是如何帶回的?

函數(shù)的返回值通過eax寄存器帶回。

7.函數(shù)是怎樣在棧區(qū)上開辟和釋放空間的?

函數(shù)通過改變esp和edp的指向來創(chuàng)建和銷毀空間,空間銷毀并不會(huì)清除該空間中的數(shù)據(jù),下一次使用該空間時(shí)新數(shù)據(jù)直接覆蓋原數(shù)據(jù)即可。

到此這篇關(guān)于C語言超詳細(xì)講解函數(shù)棧幀的創(chuàng)建和銷毀的文章就介紹到這了,更多相關(guān)C語言函數(shù)棧幀內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

峨眉山市| 克拉玛依市| 大关县| 石河子市| 壤塘县| 宁陕县| 南皮县| 大理市| 临夏县| 昌黎县| 横山县| 河曲县| 黔南| 石林| 雅安市| 建阳市| 福泉市| 通州区| 抚顺县| 金秀| 巴林左旗| 襄汾县| 兴义市| 泰和县| 姜堰市| 乐昌市| 蓬安县| 永春县| 翁源县| 宕昌县| 丰都县| 扶风县| 九龙县| 萨嘎县| 延长县| 饶阳县| 邢台县| 正镶白旗| 旬邑县| 策勒县| 靖边县|