當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]我們知道C語言是一種高級語言,所謂高級語言就是要經(jīng)過翻譯才能在具體平臺上運行的程序。而編譯程序是一種比較繁瑣的程序,它要把高級語言編譯和鏈接后,成為能夠在具體平臺運行的程序。這其中有很多知識是和操作系統(tǒng)

我們知道C語言是一種高級語言,所謂高級語言就是要經(jīng)過翻譯才能在具體平臺上運行的程序。而編譯程序是一種比較繁瑣的程序,它要把高級語言編譯和鏈接后,成為能夠在具體平臺運行的程序。這其中有很多知識是和操作系統(tǒng)和具體硬件平臺相關(guān)的,如果你想弄清楚編譯程序請學(xué)習(xí)編譯原理,有一本書可以參考《linkers_and_loaders》。

我們這里只是說明一下C語言運行的環(huán)境以及和棧的關(guān)系。讓我們從匯編語言和底層硬件來了解C語言的一些概念和C語言是如何利用棧來進(jìn)控制過程調(diào)用的。

先講一下棧:

棧是這樣一種結(jié)構(gòu):本事是一段連續(xù)的內(nèi)存空間,怎么使用這樣一種內(nèi)存空間才算是起到了棧的實際作用那,首先要規(guī)定這一段連續(xù)空間的基地址,然后就從這個地址開始依次放東西。取東西時也是從最上面的開始取。按照上面的方案管理這一段存儲空間,就是發(fā)揮了棧的作用。因為棧使用的頻率實在是太高了,所以在計算機(jī)匯編層次就有專門操作棧的指令。包括push(入棧)、pop(出棧)等。

其實棧又有一些邏輯上的分類:

根據(jù)先騰出空間再用還是先用再騰空間分為:

1,滿堆棧:即入棧后堆棧指針sp指向最后一個入棧的元素。也就是sp先減一(加一)再入棧。

2,空堆棧:即入棧后堆棧指針指向最后一個入棧元素的下一個元素。也就是先入棧sp再減一(或加一)。

根據(jù)從高地址開始用還是從低地址開始用分為:

1,遞增堆棧:即堆棧一開始的地址是低地址,向高地址開始遞增。就如同一個水杯(假設(shè)上面地址大)開口的是大地址,從杯底開始裝水。自己畫一畫圖就清楚了。我就偷懶一下不畫了。

2,遞減堆棧:即堆棧一開始的地址是高地址,向低地址開始遞增。就如同還是剛才說的那個水杯,現(xiàn)在開口的是小地址,從大地址開始用,往下走,相當(dāng)于杯子口朝下。我們用的時候是把水往上一點點壓上去。呵呵呵,不過這樣的杯子就失去了用途。但在內(nèi)存上還是可以的。

那么根據(jù)這兩種分類方法,我們就可以得到四種棧的類型,而ARM920T中使用的是遞減滿堆棧。

下面重點說明c語言運行時是怎么用棧來控制函數(shù)調(diào)用過程的。

大家想一想,我們寫c語言時用到函數(shù)調(diào)用,有時候還嵌套調(diào)用很多函數(shù)。還有有些函數(shù)還需要參數(shù)和返回值。怎么處理各個函數(shù)的參數(shù)和返回值,以及當(dāng)每一個函數(shù)完成工作時該返回到那個地方。這些都是要解決的問題。當(dāng)然最容易想到的也是必須做的是在進(jìn)行調(diào)用跳轉(zhuǎn)之前,把我這個函數(shù)現(xiàn)有的狀態(tài)保存起來,保存什么那,調(diào)用函數(shù)返回后的下一條指令,還有我這個函數(shù)需要的哪些數(shù)據(jù)。還有就是保存這些信息到哪些地方哪?這些都是我們要解決的問題。還有就是你不光要保存這些信息,還要保存這些信息的順序。因為函數(shù)調(diào)用本身有順序,你像a調(diào)用b,b又接著調(diào)用c。在c執(zhí)行完后要返回到b,b執(zhí)行完再返回a。呵呵,有順序。

我們一一想辦法來解決,當(dāng)然別人已經(jīng)用棧的策略解決的很完美了,我們只是想一些更簡潔的最容易想起來的但是不完善的方法,也正說明了人家的策略是多么的優(yōu)秀。

關(guān)于調(diào)用函數(shù)的問題,我們可以把返回地址保存到一些地方,當(dāng)然程序員知道在那?還知道順序,再根據(jù)順序返回就好了,但做這樣的工作太累了,除了寫程序還要記這些東西。哎肯定不好也不這樣做。關(guān)于傳參,有這樣可以考慮的,用專門規(guī)定好的寄存器來做傳參。行,但有缺陷,如果傳的參數(shù)很多或者是變化的,就不好用寄存器傳參了。而且我們有操作系統(tǒng)時往往要求編譯器產(chǎn)生的代碼具有可重入性,也就是保證代碼和數(shù)據(jù)的相對獨立性。一個函數(shù)被調(diào)用兩次,都有兩次的參數(shù)環(huán)境。到底現(xiàn)在我們是怎么做的那。答案是用棧。

怎么用,嘻嘻,下面一一道來:

函數(shù)在執(zhí)行一個函數(shù)調(diào)用調(diào)用時,用棧不僅保存函數(shù)的返回地址,并且一起把函數(shù)所需要的參數(shù)和返回值都保存在堆棧中。

也就是每一個函數(shù)都有一個這樣的棧,保存著一些信息。先說一下棧幀的概念,在函數(shù)調(diào)用過程中要保存的整個參數(shù)集合,包括返回地址稱作一個棧幀。

如上圖所示,我們以這個圖為例,分析一下棧在函數(shù)調(diào)用中的應(yīng)用。函數(shù)p有兩個參數(shù) x1、x2,函數(shù)p 調(diào)用函數(shù)q ,且有兩個參數(shù)。儲存在棧幀的第一幀是上一個棧幀的地址,當(dāng)前棧幀的地址就是正在使用的棧幀的基值,使用這個指針能方便的找到函數(shù)所需的變量和參數(shù)等。那為什么每一針的第一個地址要保存上一個棧幀的地址那,和保存返回地址一個初衷,當(dāng)你當(dāng)前用的棧幀用完時,把在當(dāng)前棧幀保存的上一個棧幀的地址取出就還原了上一個棧幀。

接著是返回地址,如果函數(shù)有返回值的話,返回值放在返回地址的下面。接著為函數(shù)所需要的變量申請空間。

下面說說函數(shù)p調(diào)用函數(shù)q時的具體情況。當(dāng)執(zhí)行call q(y1)時,會為函數(shù)q創(chuàng)建一個新的棧幀,具體過程是:先保存丄一幀的地址,如果有返回值的話為返回值分配存儲空間,然后保存返回地址。然后為y1分配空間并把它初始化為調(diào)用q時給的參數(shù)。接著分配另一個參數(shù)的空間y2,這個參數(shù)用于在函數(shù)內(nèi)部計算。

在任何狀態(tài)下,都有一個當(dāng)前棧幀的指針fp,這個指針用來保存當(dāng)前棧幀的地址,那這個值怎么保證是當(dāng)前的那,先說q函數(shù)的吧,是把棧的指針sp先保存下來,然后接著保存fp。然后把fp的值改為sp-4 ,因為我們知道每個棧幀的第一個要保存的是fp。

其實整個過程是動態(tài)的,所謂我說是動態(tài)的是因為sp指針一直是快速移動的。所以要在每一幀開始的時候先把這個sp保存住。然后往減4的地址處放fp。當(dāng)這個棧幀全彈出時,就把你保存的fp又恢復(fù)到原來你保存的fp了。就一直有fp代表當(dāng)前棧幀底部。也是唯一一個不變的基地址,用它來找其他的變量。

好了,下面我們看一個在ARM下C語言寫的程序然后編譯成匯編語言分析其棧的應(yīng)用。(在linux2.4內(nèi)核下寫的c語言程序,用arm-linux-gcc3.4.1編譯器編譯)

C語言源程序如下:

#include

int max(int,int);

int main(int argc,char *argv[])

{

int a=3,b=5;

max(a,b);

return 0;

}

int max(int x,int y)

{

if(x>y)

return x;

else

return y

}

函數(shù)很簡單,在主函數(shù)里調(diào)用一個外部函數(shù)max用于兩個數(shù)中數(shù)值較大的那個數(shù)并返回。

下面看ARM的匯編是怎么實現(xiàn)的這些功能,以及這中間棧的使用情況。

.file "max.c"

.text

.align 2

.global main

.type main, %function

main:

@ args = 0, pretend = 0, frame = 16

@ frame_needed = 1, uses_anonymous_args = 0

mov ip, sp

stmfd sp!, {fp, ip, lr, pc}

sub fp, ip, #4

sub sp, sp, #16

str r0, [fp, #-16]

str r1, [fp, #-20]

mov r3, #3

str r3, [fp, #-24]

mov r3, #5

str r3, [fp, #-28]

ldr r0, [fp, #-24]

ldr r1, [fp, #-28]

bl max //開始調(diào)用max函數(shù)

mov r3, #0

mov r0, r3

sub sp, fp, #12

ldmfd sp, {fp, sp, pc}

.size main, .-main

.align 2

.global max

.type max, %function

max:

@ args = 0, pretend = 0, frame = 12

@ frame_needed = 1, uses_anonymous_args = 0

mov ip, sp

stmfd sp!, {fp, ip, lr, pc}

sub fp, ip, #4

sub sp, sp, #12

str r0, [fp, #-16]

str r1, [fp, #-20]

ldr r2, [fp, #-16]

ldr r3, [fp, #-20]

cmp r2, r3

ble .L3

ldr r3, [fp, #-16]

str

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉