欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

【C語言】你知道程序是如何調(diào)用函數(shù)的嗎?-創(chuàng)新互聯(lián)

目錄

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:域名與空間、雅安服務(wù)器托管、營銷軟件、網(wǎng)站建設(shè)、晉江網(wǎng)站維護、網(wǎng)站推廣。

1.函數(shù)棧幀的含義

概念?

要用到的匯編語言的知識

示例

2.理解棧幀

2.1 main函數(shù)棧幀的創(chuàng)建

2.2 局部變量的創(chuàng)建

2.3 函數(shù)傳參

2.4 調(diào)用函數(shù)

2.5 函數(shù)返回?


? 一個.c文件在調(diào)用函數(shù)的時候(包括main 函數(shù)),其內(nèi)存中的棧區(qū)有什么變化?要壓棧、出棧哪些寄存器呢?函數(shù)的參數(shù)是如何進行傳遞的呢?函數(shù)調(diào)用結(jié)束之后棧區(qū)又是如何變化的呢?本文通過使用匯編語言,對這些內(nèi)容進行了較為詳細的剖析。

1.函數(shù)棧幀的含義 概念?

??首先,棧的概念想必不需要過多解釋,那么什么是棧幀?引用百度百科:C語言中,每個棧幀對應(yīng)著一個未運行完的函數(shù)。棧幀中保存了該函數(shù)的返回地址和局部變量。從這句話中,可以提煉以下幾點信息:

· 棧幀是一塊因函數(shù)運行而臨時開辟的空間。
· 每調(diào)用一次函數(shù)便會創(chuàng)建一個獨立棧幀。
· 棧幀中存放的是函數(shù)中的必要信息,如局部變量、函數(shù)傳參、返回值等。
· 當(dāng)函數(shù)運行完畢棧幀將會銷毀。

? 我們知道,C語言的內(nèi)存區(qū)分成了 靜態(tài)區(qū)、棧區(qū)、堆區(qū),函數(shù)棧幀無疑是在棧區(qū)創(chuàng)建和銷毀的,所以其要符合?!昂筮M先出”的特點。

要用到的匯編語言的知識

? 在這里使用匯編語言方面知識的原因是:通過它,我們可以深入底層了解一個程序是如何運行的,在何時——什么東西壓棧,什么東西出棧,寄存器(匯編語言中一些用來暫時存儲數(shù)據(jù)的東西)如何變化等等。這些都是C語言無法直觀體現(xiàn)的,我們可以通過Visual Stdio 的在調(diào)試時的反匯編功能,將C語言代碼轉(zhuǎn)換成匯編語言代碼,以便更好地觀察。(另,C語言也是匯編語言編寫的。)所以,簡單地說,本文主要是在分析匯編語言的執(zhí)行過程。

? 我們首先要了解幾個匯編語言方面的東西,其中ESP和EBP時專門維護函數(shù)棧幀的,分別指向棧頂和棧底:

寄存器?用途
EAX累加寄存器:用于乘除法、函數(shù)返回值
EBX用于存放內(nèi)存數(shù)據(jù)指針
ECX計數(shù)器
EDX用于乘除法、IO指針
ESP存放棧頂指針(其值是地址)
EBP存放棧底指針(其值是地址)

匯編指令用途
movmov A,B 將數(shù)據(jù)B移動到A
push壓棧
pop出棧
call函數(shù)調(diào)用
add加法
sub減法
rep重復(fù)
lea加載有效地址

示例

? 比如,我們寫下一個如下的C語言程序,非常容易,只有main() 函數(shù)和一個 Add() 函數(shù),主函數(shù)里面調(diào)用了 Add() 。

#includeint Add(int x, int y)
{
	return x + y;
}

int main()
{
	int a = 10;
	int b = 20;
	int c = Add(a, b);
	return 0;
}

? 那么,一開始調(diào)用主函數(shù)的時候,主函數(shù)的函數(shù)棧幀就壓棧;然后在主函數(shù)里面,調(diào)用了Add() 函數(shù),此時Add() 的函數(shù)棧幀也要壓棧。那么現(xiàn)在面臨一個問題,是維護Add() 函數(shù),還是維護main() 函數(shù),亦或兩者都維護?
? 其實,從平時使用Visual Stdio 調(diào)試的時候就可以看出來,當(dāng)主函數(shù)內(nèi)部調(diào)用一個函數(shù)A,按F11分步調(diào)試,會進入函數(shù)A的內(nèi)部,函數(shù)A調(diào)用結(jié)束,會返回主函數(shù)。同理,實際上從進入函數(shù)A,一直到A 函數(shù)調(diào)用結(jié)束,這個過程都在維護函數(shù)A。所以,在main() 函數(shù)內(nèi)部調(diào)用 Add() 函數(shù)之后,會出現(xiàn)如下圖所示的情況,ebp和esp來維護Add() 函數(shù)的棧幀。當(dāng)Add() 函數(shù)調(diào)用結(jié)束,它的函數(shù)棧幀自然就會出棧,此時ebp、esp又會返回維護main() 函數(shù)的棧幀。

2.理解棧幀 2.1 main函數(shù)棧幀的創(chuàng)建

? 實際上,main() 函數(shù)也是由其他函數(shù)調(diào)用的,其調(diào)用鏈條如下:

? 創(chuàng)建main函數(shù)的函數(shù)棧幀代碼如下,匯編語言的注釋是用 ; 所以這里 ; 后面的內(nèi)容是注釋,幫助理解代碼。

006117A0  push        ebp                 ; ebp 壓棧
006117A1  mov         ebp,esp             ; 將 esp里面的值 賦給ebp
006117A3  sub         esp,0E4h            ; esp減去0E4h(十六進制),得到的結(jié)果賦給esp
006117A9  push        ebx                 ; ebx 壓棧
006117AA  push        esi                 ; esi 壓棧
006117AB  push        edi                 ; edi 壓棧
006117AC  mov         edi,[ebp-24h]       ; 將ebp往上數(shù),第24h(16進制)個字節(jié)開始,向下4個字節(jié)的值賦給edi
006117AF  mov         ecx,9               ; 這里到結(jié)束的意思是:
006117B4  mov         eax,0CCCCCCCCh      ; 將0CCCCCCCCh 賦值給某塊空間,這塊空間從附加段中 edi 指向的位置開始
006117B9  rep stos    dword ptr es:[edi]  ; 一共執(zhí)行九次(0CCCCCCCCh 是四個字節(jié)的內(nèi)容,每次操作四個字節(jié),所以一共操作了36字節(jié))

第一行?

? 我們來開始逐句剖析上方代碼,首先執(zhí)行第一行(圖中紅色圓圈圈出來的黃色箭頭,表示已經(jīng)執(zhí)行完其上一行,按F10調(diào)試就執(zhí)行當(dāng)前行),由于是壓棧操作,所以esp的值會有所變化,如下圖右邊監(jiān)視窗口,esp的值(十六進制顯示的)相較之前改變了,所以變成紅色:

? 如下,ebp壓棧,同時esp上移:

第二行

該行是將esp的值賦給ebp,效果也如下圖,右邊監(jiān)視窗口的紅色部分所示。

? 如下,將esp的值賦給ebp之后,ebp和esp指向同一塊地方:

第三行

? 該行是將esp的值減去0E4h(十六進制),得到的結(jié)果賦給esp,如下圖。

如圖所示,由于圖中從下往上是地址高處到地址低處,所以esp值變小,實際上圖中是上移。并且,現(xiàn)在ebp和esp維護的空間,就是main函數(shù)的函數(shù)棧幀:

第四行

? 壓棧,壓入ebx,改變棧頂指針esp的值。

? 如下,壓棧,esp上移:

第五行

? 壓入esi,改變esp的值。

? 如下,和上一步類似:

第六行

? 壓入edi,改變esp的值。?

? 和上一步也類似:

第七行

? 將[ebp-24h] 表示的地址賦值給edi。

? 這里就是把 edi 里面的值改變,從函數(shù)棧幀看不出什么,看上面的監(jiān)視圖就可以直到確實是改變了。

最后三行

? 如之前代碼里的注釋所說。

? 如下,兩個箭頭指示的值是一樣的,其代表的是edi所表示的地址,從該地址開始,往后9個dw(double word 雙字,一個雙字等于四個字節(jié))的內(nèi)容,都賦值為cccccccc (十六進制)。

? 這三行代碼效果如下:

? 整個過程可以用一張動圖生動形象地展示:

2.2 局部變量的創(chuàng)建

? 接下來,我們在匯編代碼中鼠標(biāo)右擊,然后將下圖紅色箭頭所指示的"顯示符號名" 的勾去掉。

? 發(fā)生改變的是下圖中紅色圓圈圈出來的,可以看出,原本所有的變量名,都變成了寄存器減去某個十六進制數(shù)字。他們實際上是等價的,即變量的地址就等于替換后的地址。

? 接下來分析局部變量創(chuàng)建過程。
? 首先,創(chuàng)建變量a,代碼如下,其含義就是,將0Ah 這個十六進制數(shù)字,從ebp的地址低八位處開始放,占四個字節(jié):

002C17C5  mov         dword ptr [ebp-8],0Ah

? 如下圖,可以通過兩個紅色箭頭看到,右邊監(jiān)視的ebp的值就是左邊 地址處的箭頭指向的地址,說明這就是ebp的地址,然后減去八位,再根據(jù)棧從下往上使用以及Visual Stdio小端存儲的特點,就成了內(nèi)存區(qū)里面紅色方框框出來的內(nèi)容。(注意,比如 cc cc cc cc ,cc占據(jù)的是一個字節(jié)的空間,四個cc 就占據(jù)四個字節(jié),而匯編語言中,地址-1,只跳過一個c,所以ebp-8是跳過8個c,即四個字節(jié))

? 如下,圖中一個小格子代表四個字節(jié),不難看出,變量a存儲的位置,在棧底指針往上跳過四個字節(jié)的地方。

? 然后創(chuàng)建局部變量b,通過內(nèi)存圖可以看出,變量b和變量a是間隔八個字節(jié)的:

? 如下圖:

2.3 函數(shù)傳參

? 代碼如下:

002C17D3  mov         eax,dword ptr [ebp-14h]   ; 將變量b的值賦給eax
002C17D6  push        eax                       ; eax壓棧
002C17D7  mov         ecx,dword ptr [ebp-8]     ; 將變量a的值賦給ecx
002C17DA  push        ecx                       ; ecx壓棧

? 執(zhí)行前兩行代碼,確實將變量b的值賦給了eax,然后eax引起的壓棧導(dǎo)致了esp改變:

? 如下圖,不要忘了eax里面的值和變量b是一樣的哦:

? 執(zhí)行后兩行代碼:

? 其效果和前兩行類似,同時ecx里面存的是變量a的值:

2.4 調(diào)用函數(shù)

? 上面的內(nèi)容執(zhí)行完之后,要執(zhí)行如下語句,其意思是,執(zhí)行?002C10B4 地址處的內(nèi)容:

002C17DB  call        002C10B4

? 然后我們將其滑倒該地,發(fā)現(xiàn)是這樣的,意思是跳到002C1740地址處:

又找到該地址,發(fā)現(xiàn)如下,所以,通過這兩步調(diào)用Add() 函數(shù),如下紅色部分,和創(chuàng)建main函數(shù)的函數(shù)棧幀類似,實際上就是創(chuàng)建了Add() 的函數(shù)棧幀:

? 效果如下,建立了Add函數(shù)的函數(shù)棧幀:

? 紅色個方框后面兩行代碼不是很重要,是用來檢查bug的,如下代碼和圖片:

002C1757  mov         ecx,2CC003h  
002C175C  call        002C130C

2.5 函數(shù)返回?

? 函數(shù)返回:

002C1761  mov         eax,dword ptr [ebp+8]   
002C1764  add         eax,dword ptr [ebp+0Ch]

? 第一行代碼:?將ebp+8 地址處的數(shù)據(jù)放到eax?。

? 第二行代碼:將ebp+0Ch 地址處的數(shù)據(jù)和eax相加,結(jié)果存到eax里面。

? 如下圖中,由于圖片從下往上是地址從高到低,所以圖片中ebp+8是在ebp下方。實際上就是ecx和eax的值相加,然后存到eax里面。eax里面存儲變量b的值,ecx里面存儲變量a的值,最后eax的值就是變量a、b之和。并且eax是不會隨著Add() 函數(shù)的函數(shù)棧幀銷毀而改變值。

? 通過監(jiān)視也可以看出,eax的值變成0x0000001e,轉(zhuǎn)換成十進制就是30。

? 此時已經(jīng)拿到返回值,存儲在eax里面,還要執(zhí)行以下幾行代碼:

00AA13F1  pop         edi  
00AA13F2  pop         esi  
00AA13F3  pop         ebx  
00AA13F4  mov         esp,ebp  
00AA13F6  pop         ebp  
00AA13F7  ret

就是出棧、賦值等等,結(jié)果如下,回到了調(diào)用Add() 函數(shù)之前的狀態(tài):

? 然后執(zhí)行main() 函數(shù)后續(xù)代碼代碼,如下圖紅色框出:

? 第一行:esp加8,即esp在途中向下移動四個字節(jié)。

? 第二行,將eax的值賦給ebp-20h 地址處。

? 執(zhí)行完之后,調(diào)試圖如下,通過對比兩個紅色方框的內(nèi)容,左邊紅色方框的地址,和右邊&c 的值一樣,說明那就是變量c 存儲的地方,其值也是變量c 的值:

? 示意圖如下:

? 通過對函數(shù)棧幀創(chuàng)建、銷毀過程的剖析使我們不僅了解計算機做了什么,還了解了它是如何做的。通過函數(shù)棧幀嘗試解析遞歸等問題相信也會更加直觀。由于本人水平有限,不足之處還請大家多多指教。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

當(dāng)前題目:【C語言】你知道程序是如何調(diào)用函數(shù)的嗎?-創(chuàng)新互聯(lián)
文章URL:http://chinadenli.net/article22/ddiojc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計、外貿(mào)建站、響應(yīng)式網(wǎng)站、網(wǎng)站設(shè)計公司、ChatGPT、搜索引擎優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化