1什么是棧
百度這么說:棧是一種特殊的線性表,是一種只允許在表的一端進行插入或刪除操作的線性表。表中允許進行插入、刪除操作的一端稱為棧頂。表的另一端稱為棧底。棧頂?shù)漠斍拔恢檬莿討B(tài)的,對棧頂當前位置的標記稱為棧頂指針。當棧中沒有數(shù)據(jù)元素時,稱之為空棧。棧的插入操作通常稱為進?;蛉霔?,棧的刪除操作通常稱為退?;虺鰲?。
簡易理解:
客棧,即臨時寄存的地方,計算機中的堆棧主要用來保存臨時數(shù)據(jù),局部變量和中斷/調(diào)用子程序程序的返回地址。程序中棧主要是用來存儲函數(shù)中的局部變量以及保存寄存器參數(shù)的,如果你用了操作系統(tǒng),棧中還可能存儲當前進線程的上下文。設(shè)置棧大小的一個原則是,保證棧不會下溢出到數(shù)據(jù)空間或程序空間.CPU在運行程序時,會自動的使用堆棧,所以堆棧指針SP就必須要在調(diào)用C程序前設(shè)定。
CPU的內(nèi)存RAM空間存放規(guī)律一般是分段的,從地址向高地址,依次為:程序段(.text)、BSS段,上面還可能會有堆空間,然后最上面才是堆棧段。這樣安排堆棧,是因為堆棧的特點決定的,堆棧的指針SP初始化一般在堆棧段的高地址,也就是內(nèi)存的高地址,然后讓堆棧指針向下增長(其實就是遞減)。
這樣做的好處就是堆??臻g遠離了其他段,不會跟其他段重疊,造成修改其他段數(shù)據(jù),而引起不可預(yù)料的后果,還有設(shè)置堆棧大小的原則,要保證棧不會下溢出到數(shù)據(jù)空間或者程序空間。所謂堆棧溢出,是指堆棧指針SP向下增長到其他段空間,如果棧指針向下增長到其他段空間,稱為堆棧溢出。堆棧溢出會修改其他空間的值,嚴重情況下可造成死機.
2堆棧指針的設(shè)置
開始將堆棧指針設(shè)置在內(nèi)部RAM,是因為不是每個板上都有外部RAM,而且外部RAM的大小也不相同,而且如果是SDRAM,還需要初始化,在內(nèi)部RAM開始運行的一般是一個小的引導(dǎo)程序,基本上不怎么使用堆棧,因此將堆棧設(shè)置在內(nèi)部RAM,但這也就要去改引導(dǎo)程序不能隨意使用大量局部變量。
片內(nèi)4K的SRAM,SDRAM大小64M,從0x30000000到0x33FFFFFF,當程序在片內(nèi)SRAM運行的時候,sp的值設(shè)置為4096,當程序在SDRAM內(nèi)運行的時候sp設(shè)置為0x34000000,當程序在內(nèi)部SRAM運行,若已經(jīng)初始化SDRAM,此時也可以將堆棧指針設(shè)置為0x34000000,更加防止了堆棧溢出。
3棧的整體作用
保存現(xiàn)場;
傳遞參數(shù):匯編代碼調(diào)用 C 函數(shù)時,需傳遞參數(shù);
保存臨時變量:包括函數(shù)的非靜態(tài)局部變量以及編譯器自動生成的其他臨時變量;
1) 保存現(xiàn)場
現(xiàn)場,意思就相當于案發(fā)現(xiàn)場,總有一些現(xiàn)場的情況,要記錄下來的,否則被別人破壞掉之后,你就無法恢復(fù)現(xiàn)場了。而此處說的現(xiàn)場,就是指 CPU 運行的時候,用到了一些寄存器,比如 r0,r1 等等,對于這些寄存器的值,如果你不保存而直接跳轉(zhuǎn)到子函數(shù)中去執(zhí)行,那么很可能就被其破壞了,因為其函數(shù)執(zhí)行也要用到這些寄存器。因此,在函數(shù)調(diào)用之前,應(yīng)該將這些寄存器等現(xiàn)場,暫時保持起來(入棧 push),等調(diào)用函數(shù)執(zhí)行完畢返回后(出棧 pop),再恢復(fù)現(xiàn)場。這樣CPU就可以正確的繼續(xù)執(zhí)行了。
保存寄存器的值,一般用的是 push 指令,將對應(yīng)的某些寄存器的值,一個個放到棧中,把對應(yīng)的值壓入到棧里面,即所謂的壓棧。然后待被調(diào)用的子函數(shù)執(zhí)行完畢的時候,再調(diào)用 pop,把棧中的一個個的值,賦值給對應(yīng)的那些你剛開始壓棧時用到的寄存器,把對應(yīng)的值從棧中彈出去,即所謂的出棧。其中保存的寄存器中,也包括 lr 的值(因為用 bl 指令進行跳轉(zhuǎn)的話,那么之前的 PC 的值是存在 lr 中的),然后在子程序執(zhí)行完畢的時候,再把棧中的 lr 的值 pop 出來,賦值給 PC,這樣就實現(xiàn)了子函數(shù)的正確的返回
2) 傳遞參數(shù)
C 語言進行函數(shù)調(diào)用的時候,常常會傳遞給被調(diào)用的函數(shù)一些參數(shù),對于這些 C 語言級別的參數(shù),被編譯器翻譯成匯編語言的時候,就要找個地方存放一下,并且讓被調(diào)用的函數(shù)能夠訪問,否則就沒發(fā)實現(xiàn)傳遞參數(shù)了。對于找個地方放一下,分兩種情況。一種情況是,本身傳遞的參數(shù)不多于 4 個,就可以通過寄存器 r0~r3 傳送參數(shù)。因為在前面的保存現(xiàn)場的動作中,已經(jīng)保存好了對應(yīng)的寄存器的值,那么此時,這些寄存器就是空閑的,可以供我們使用的了,那就可以放參數(shù)。另一種情況是,參數(shù)多于 4 個時,寄存器不夠用,就得用棧了。
3) 臨時變量保存在棧中
包括函數(shù)的非靜態(tài)局部變量以及編譯器自動生成的其他臨時變量。
-
ARM
+關(guān)注
關(guān)注
134文章
8967瀏覽量
365042 -
寄存器
+關(guān)注
關(guān)注
31文章
5253瀏覽量
119205 -
C語言
+關(guān)注
關(guān)注
180文章
7575瀏覽量
134092 -
指針
+關(guān)注
關(guān)注
1文章
475瀏覽量
70457
原文標題:C語言及ARM中堆棧指針SP設(shè)置的理解與總結(jié)
文章出處:【微信號:mcuworld,微信公眾號:嵌入式資訊精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論