c語(yǔ)言函數(shù)調(diào)用棧幀動(dòng)畫(huà),運(yùn)行時(shí)棧幀結(jié)構(gòu)

C語(yǔ)言棧的調(diào)用。

程序中,一個(gè)函數(shù)是一個(gè)過(guò)程,這個(gè)過(guò)程可以分為包括傳入?yún)?shù)、過(guò)程代碼、返回三部分構(gòu)成。由于一個(gè)函數(shù)過(guò)程需要用到內(nèi)部變量、臨時(shí)變量等,所以需要在進(jìn)程空間的??臻g分配一段存儲(chǔ)片段來(lái)存儲(chǔ)函數(shù)過(guò)程中的這些參數(shù),該內(nèi)存片段即為棧幀。

在大余等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專(zhuān)注、極致的服務(wù)理念,為客戶(hù)提供成都做網(wǎng)站、網(wǎng)站制作 網(wǎng)站設(shè)計(jì)制作按需網(wǎng)站策劃,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),營(yíng)銷(xiāo)型網(wǎng)站建設(shè),外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè),大余網(wǎng)站建設(shè)費(fèi)用合理。

棧幀的由來(lái):

為一個(gè)函數(shù)的過(guò)程提供一個(gè)存儲(chǔ)函數(shù)局部變量,參數(shù),返回地址和其他臨時(shí)變量;

棧幀的周期:

進(jìn)入函數(shù)~函數(shù)返回,該階段內(nèi)棧幀作為

不同的語(yǔ)言具體的實(shí)現(xiàn)方式略有不同,但是,總體上,fun(a,b);

局部變量:

包括函數(shù)傳入的形參和函數(shù)內(nèi)部定義的變量;

返回地址:

指令指針p指向call

fun,那么fun棧幀存儲(chǔ)的返回地址為p+1;現(xiàn)今的編譯器的一個(gè)約定是將返回地址存到一個(gè)固定的寄存器中,這樣比讀取棧幀(內(nèi)存)效率要高。

臨時(shí)變量:

主要為計(jì)算,運(yùn)算過(guò)程中的中間臨時(shí)變量;

參數(shù)傳遞:

其一:如果fun中調(diào)用另一個(gè)函數(shù)k(a,b...n);那么,傳遞的參數(shù)是形參,按照現(xiàn)代編譯規(guī)定,前k個(gè)形參是通過(guò)寄存器傳遞,后n-k個(gè)形參通過(guò)棧幀的實(shí)參部分(棧幀的尾部)來(lái)傳遞;

其二:主要為在fun中要調(diào)用函數(shù)g(a,b),那么為g()函數(shù)傳出實(shí)參(形參是通過(guò)寄存器來(lái)傳遞的)是通過(guò)“傳出實(shí)參”區(qū)塊進(jìn)行的,這么做主要是為了保證該實(shí)參能夠被內(nèi)層嵌套的函數(shù)訪(fǎng)問(wèn)。比如,g函數(shù)由調(diào)用一個(gè)k(a地址)函數(shù),同樣需要用到a的地址,所以fun在傳遞參數(shù)時(shí)必須為實(shí)參(a)傳遞申請(qǐng)固定的內(nèi)存存儲(chǔ)空間(而非用寄存器)這樣k函數(shù)可以通過(guò)固定的內(nèi)存地址(fun的形參列表來(lái)獲取參數(shù)值)。這時(shí)的g的棧幀為fun棧幀的下一幀(相鄰的空間地址),即調(diào)用者和被調(diào)用者的棧幀是相連的;

保護(hù)的寄存器:

棧幀作為函數(shù)過(guò)程的一個(gè)臨時(shí)內(nèi)存存儲(chǔ)區(qū)塊,同時(shí)負(fù)責(zé)函數(shù)調(diào)用過(guò)程中寄存器值的保存和還原。即:假設(shè)fun函數(shù)目前占用了寄存器ri存儲(chǔ)一個(gè)臨時(shí)變量t,而此時(shí)調(diào)用了函數(shù)g(),在g()函數(shù)中可能需要用到寄存器ri做運(yùn)算的臨時(shí)存儲(chǔ),那么如何確保g()函數(shù)調(diào)用返回后,ri恢復(fù)到fun中t的原來(lái)值。這就需要在調(diào)用者或者被調(diào)用者中選擇其一來(lái)保存原有ri的值,即caller-save或者callee-save。

C語(yǔ)言函數(shù)調(diào)用棧

程序的執(zhí)行過(guò)程可看作連續(xù)的函數(shù)調(diào)用。當(dāng)一個(gè)函數(shù)執(zhí)行完畢時(shí),程序要回到調(diào)用指令的下一條指令(緊接call指令)處繼續(xù)執(zhí)行。函數(shù)調(diào)用過(guò)程通常使用堆棧實(shí)現(xiàn),每個(gè)用戶(hù)態(tài)進(jìn)程對(duì)應(yīng)一個(gè)調(diào)用棧結(jié)構(gòu)(call stack)。編譯器使用堆棧傳遞函數(shù)參數(shù)、保存返回地址、臨時(shí)保存寄存器原有值(即函數(shù)調(diào)用的上下文)以備恢復(fù)以及存儲(chǔ)本地局部變量。

不同處理器和編譯器的堆棧布局、函數(shù)調(diào)用方法都可能不同,但堆棧的基本概念是一樣的。

寄存器是處理器加工數(shù)據(jù)或運(yùn)行程序的重要載體,用于存放程序執(zhí)行中用到的數(shù)據(jù)和指令。因此函數(shù)調(diào)用棧的實(shí)現(xiàn)與處理器寄存器組密切相關(guān)。

AX(AH、AL):累加器。有些指令約定以AX(或AL)為源或目的寄存器。輸入/輸出指令必須通過(guò)AX或AL實(shí)現(xiàn),例如:端口地址為43H的內(nèi)容讀入CPU的指令為INAL,43H或INAX,43H。目的操作數(shù)只能是AL/AX,而不能是其他的寄存器。 [5]

BX(BH、BL): 基址寄存器 。BX可用作間接尋址的地址寄存器和 基地址寄存器 ,BH、BL可用作8位通用數(shù)據(jù)寄存器。 [5]

CX(CH、CL):計(jì)數(shù)寄存器。CX在循環(huán)和串操作中充當(dāng)計(jì)數(shù)器,指令執(zhí)行后CX內(nèi)容自動(dòng)修改,因此稱(chēng)為計(jì)數(shù)寄存器。 [5]

DX(DH、DL):數(shù)據(jù)寄存器。除用作通用寄存器外,在 I/O指令 中可用作端口 地址寄存器 ,乘除指令中用作輔助累加器。 [5]

2.指針和 變址寄存器

BP( Base Pointer Register):基址指針寄存器。 [5]

SP( Stack Pointer Register): 堆棧指針寄存器 。 [5]

SI( Source Index Register):源變址寄存器。 [5]

DI( Destination Index Register):目的變址寄存器。 [5]

函數(shù)調(diào)用棧的典型內(nèi)存布局如下圖所示:

圖中給出主調(diào)函數(shù)(caller)和被調(diào)函數(shù)(callee)的棧幀布局,"m(%ebp)"表示以EBP為基地址、偏移量為m字節(jié)的內(nèi)存空間(中的內(nèi)容)。該圖基于兩個(gè)假設(shè):第一,函數(shù)返回值不是結(jié)構(gòu)體或聯(lián)合體,否則第一個(gè)參數(shù)將位于"12(%ebp)" 處;第二,每個(gè)參數(shù)都是4字節(jié)大小(棧的粒度為4字節(jié))。在本文后續(xù)章節(jié)將就參數(shù)的傳遞和大小問(wèn)題做進(jìn)一步的探討。 此外,函數(shù)可以沒(méi)有參數(shù)和局部變量,故圖中“Argument(參數(shù))”和“Local Variable(局部變量)”不是函數(shù)棧幀結(jié)構(gòu)的必需部分。

其中,主調(diào)函數(shù)將參數(shù)按照調(diào)用約定依次入棧(圖中為從右到左),然后將指令指針EIP入棧以保存主調(diào)函數(shù)的返回地址(下一條待執(zhí)行指令的地址)。進(jìn)入被調(diào)函數(shù)時(shí),被調(diào)函數(shù)將主調(diào)函數(shù)的幀基指針EBP入棧,并將主調(diào)函數(shù)的棧頂指針ESP值賦給被調(diào)函數(shù)的EBP(作為被調(diào)函數(shù)的棧底),接著改變ESP值來(lái)為函數(shù)局部變量預(yù)留空間。此時(shí)被調(diào)函數(shù)幀基指針指向被調(diào)函數(shù)的棧底。以該地址為基準(zhǔn),向上(棧底方向)可獲取主調(diào)函數(shù)的返回地址、參數(shù)值,向下(棧頂方向)能獲取被調(diào)函數(shù)的局部變量值,而該地址處又存放著上一層主調(diào)函數(shù)的幀基指針值。本級(jí)調(diào)用結(jié)束后,將EBP指針值賦給ESP,使ESP再次指向被調(diào)函數(shù)棧底以釋放局部變量;再將已壓棧的主調(diào)函數(shù)幀基指針彈出到EBP,并彈出返回地址到EIP。ESP繼續(xù)上移越過(guò)參數(shù),最終回到函數(shù)調(diào)用前的狀態(tài),即恢復(fù)原來(lái)主調(diào)函數(shù)的棧幀。如此遞歸便形成函數(shù)調(diào)用棧。

EBP指針在當(dāng)前函數(shù)運(yùn)行過(guò)程中(未調(diào)用其他函數(shù)時(shí))保持不變。在函數(shù)調(diào)用前,ESP指針指向棧頂?shù)刂?,也是棧底地址。在函?shù)完成現(xiàn)場(chǎng)保護(hù)之類(lèi)的初始化工作后,ESP會(huì)始終指向當(dāng)前函數(shù)棧幀的棧頂,此時(shí),若

傳智的老師講C語(yǔ)言函數(shù)的棧幀調(diào)用過(guò)程講錯(cuò)了吧?大家進(jìn)來(lái)看看

你的老師是沒(méi)說(shuō)錯(cuò)的。棧的規(guī)則是先進(jìn)后出,后進(jìn)先出。進(jìn)入棧不代表會(huì)運(yùn)行,它只是進(jìn)入了1個(gè)運(yùn)行的隊(duì)列。按照你的方法那這個(gè)棧基本沒(méi)意義了,因?yàn)槟闶沁M(jìn)棧就出棧了,直接就運(yùn)行了。并沒(méi)有一個(gè)隊(duì)列順序。

1、printf(n2)它最先進(jìn)棧,所以它的排在隊(duì)列的最后面,它最后運(yùn)行。這符合程序的運(yùn)行順序

2、printf(n1)它第二進(jìn)棧,所以它是倒數(shù)第二個(gè)運(yùn)行的。以此類(lèi)推下去。

3、如果按照你的說(shuō)法,main最先進(jìn)棧,你會(huì)發(fā)現(xiàn)它是在棧的底部,它無(wú)法最先運(yùn)行。因?yàn)樗厦孢€有你說(shuō)的printf1,2,3,4,5等等。先出棧也是它們,意味著先運(yùn)行也是它們。這和事實(shí)不符的。因?yàn)檫\(yùn)行一個(gè)程序是從主函數(shù)開(kāi)始運(yùn)行的。

4、根據(jù)棧的規(guī)定,這里main應(yīng)該是最后進(jìn)棧的才對(duì),因?yàn)樗詈筮M(jìn)棧,所以他最先出棧,也是它最先運(yùn)行。

網(wǎng)頁(yè)名稱(chēng):c語(yǔ)言函數(shù)調(diào)用棧幀動(dòng)畫(huà),運(yùn)行時(shí)棧幀結(jié)構(gòu)
文章轉(zhuǎn)載:http://muchs.cn/article4/hcjooe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化全網(wǎng)營(yíng)銷(xiāo)推廣、企業(yè)網(wǎng)站制作、微信公眾號(hào)、網(wǎng)頁(yè)設(shè)計(jì)公司

廣告

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

成都app開(kāi)發(fā)公司