51堆棧的安全(精確)設置
1、編譯器、連接器把堆棧段定位在IDATA內所有段的最后面,也即內存IDATA高端;
2、中斷堆棧被定位在堆棧段內的最后面,即IDATA最頂端;所以堆棧段的安全余量設置,實(shí)際上是中斷堆棧深度的配置。
3、如果不考慮系統堆棧的安全余量設置,一個(gè)沒(méi)有二級中斷嵌套的一級中斷堆棧深度應該是13字節。——為什么?
4、系統中斷的安全余量配置應該是……字節。——為什么?
下面詳細說(shuō)明:
1、整個(gè)51內存256字節。C51首先分配全局靜態(tài)變量在IDATA低端,接著(zhù)分配的是項目中所有函數的參數和局部變量共享覆蓋區——也屬于全局靜態(tài)變量區(段)。(有沒(méi)有動(dòng)態(tài)數組區段冷漠不知道也不關(guān)心,)然后就是系統堆棧段,其棧底指針?STACK——由C51自動(dòng)生成,棧頂應該是IDATA頂端——0xFF。系統堆棧深度=0xFF-(?STACK)。
……Cx51編譯器會(huì )(自動(dòng)——冷漠注釋?zhuān)┊a(chǎn)生一個(gè)?STACK的堆棧段,該段將被自動(dòng)定位到IDATA空間的頂部。……一般不需要特別指定?STACK 的位置,對于具有幾個(gè)堆棧的匯編程序才需要采用STACK命令。需要注意的是,重新定位?STACK 段必須非常小心,因為可能會(huì )破壞 DATA 或 IDATA 空間的變量而導致程序無(wú)**常運行。
冷漠同學(xué)啊, 引用就引用吧, 干么斷章取義,還夾雜私貨, 這樣不好嘛。
1)中斷堆棧最大可能深度是15(2+5+8)字節, 不是 13。原因已經(jīng)給出, 不再重復。
2)8051 運行時(shí)有只有一個(gè)統一stack, 不存在 中斷堆棧 以及 非中斷堆棧, os 或程序人為操縱stack 另當別論。
3)堆棧段定位在IDATA所有段的最后面, 把空白區全部作為stack 這非常自然, 而且 8051 stack grow *UP*, 用腳后跟想想就會(huì )明白。c51:
While the 8051 architecture restricts the stack to internal memory, it may be located at any point therein. The stack typically starts following the last individual variable allocation in internal memory and is free to grow *up* through whatever memory remains.
4)私有堆棧是****編譯時(shí)*****的中間產(chǎn)物, 用于最后連接計算, 連接時(shí)linker 統一定位。目標代碼*****運行時(shí)*******,只有一個(gè)stack. 所有的函數調用, 中斷斷點(diǎn), 以及中斷register保護都在一個(gè) stack 里。這是最基本的****常識***問(wèn)題?。。?! os 的人為分割切換 stack 完全是另一個(gè)概念。
請教 冷漠大師:
您所言的“后臺堆棧”,實(shí)際上是C語(yǔ)言中的軟堆棧,負責分配在全局靜態(tài)變量空間共享覆蓋區,其長(cháng)度為每個(gè)獨立的后臺函數的私有堆棧之和!
您所言的“前臺堆棧”,實(shí)際是51單片機中真正的硬件堆棧,負責中斷響應需要保護的變量,子函數調用等硬性的壓棧出棧操作!
C語(yǔ)言的運行是依靠這一軟一硬兩個(gè)堆棧協(xié)調工作,您所言的:一高(端)一低(端),一小一大,一前(臺)一后(臺)。就是指這一軟一硬兩個(gè)堆棧。
不知俺理解的對不對?
提一個(gè)問(wèn)題:什么是堆棧?
如果,堆棧是指硬件堆棧,那個(gè)由堆棧指針SP所控制的,那當然只有一個(gè)堆棧,沒(méi)有什么私有的堆棧,包括中斷等,都是往這個(gè)堆棧上放,
如果自己在函數里(操作系統也不過(guò)是一些函數,一些公用的函數集而已)定義一個(gè)堆棧,那個(gè)堆棧就不好說(shuō),那叫軟堆棧。
一個(gè)處理系統有且只有一個(gè)當前堆棧,就是有SP寄存器控制的那個(gè)。不管是中斷發(fā)生還是函數調用,都是用這個(gè)SP定位。其余什么私有堆棧不過(guò)是程序修改SP而實(shí)現的。
堆棧的深度是不宜精確設置的,除非你的程序很簡(jiǎn)單,或根本就沒(méi)有中斷嵌套,這樣你可以很容易計算出系統可能最大堆棧。不然沒(méi)什么好說(shuō)的,將必要的內存設置好,其余的統統留給堆棧(反正閑著(zhù)也是閑著(zhù))。
特地說(shuō)明一點(diǎn):
“reentrant"的 "simulated stack" 只是為了模擬通過(guò) stack 傳遞參數(這是大多數c 編譯器的做法)以實(shí)現重入,實(shí)際實(shí)現上有點(diǎn)復雜,是Rn寄存器再加上一個(gè)“simulated stack" 數據區(具體情況可以看看反匯編)。
具體沒(méi)看過(guò)編譯手冊,不過(guò)對于這句有些疑問(wèn):
其棧底指針?STACK——由C51自動(dòng)生成,棧頂應該是IDATA頂端——0xFF
51堆棧是向上生長(cháng)型,剛開(kāi)始棧頂應該在棧底那里,每次PUSH,往上加,直到最大0XFF.但是你這里說(shuō)棧頂應該在IDATA的頂端--OXFF,應該不對。
負責分配在全局靜態(tài)變量空間共享覆蓋區,其長(cháng)度為每個(gè)獨立的后臺函數的私有堆棧之和!
“軟堆棧”的提法非常贊同。絕不是一般人所能理解到如此深刻的。其它先不多說(shuō),——我還沒(méi)講到。但是上面紅線(xiàn)部分我有異議:就像后臺所有非重入函數的參數傳遞和局部變量被分配在共享覆蓋區一樣,其長(cháng)度應該是占用內存字節數最多的那個(gè)函數所占有的區域,其它函數分時(shí)共享這個(gè)區域。——而不是所有之和。這才是共享、覆蓋的操作系統內存管理的方法和意義吧?
同意12樓,說(shuō)的太好了。這里確實(shí)不好得出唯一結論;記得ayb_ice詳細論證過(guò),堆棧長(cháng)度開(kāi)始為什么是1字節。建議去看看他的帖子。我不能確定唯一結論的理由:
1、?STACK是由編譯器自動(dòng)生成的系統堆棧段,——所有含有PUSH / POP指令操作的函數,都在這個(gè)系統堆棧段里享有自己的連續堆??臻g(注意是動(dòng)態(tài)的。)?STACK所指向的系統堆棧段被分配在系統所有其它RAM段的最后面。?STACK肯定是始終指向系統堆棧棧底,連接定位之后就不可移動(dòng)的;
2、“最后面的”后面還能安排有東西么?冷漠認為編譯器不可能出爾反爾,所以認為沒(méi)有了,所以冷漠說(shuō)棧頂是IDATA的頂。12樓可以說(shuō)棧頂是移動(dòng)的,移動(dòng)上限是IDATA頂端。冷漠堅決同意。
?STACK的定位是連接器確定的,和編譯器無(wú)關(guān)。LZ已經(jīng)舉了書(shū)上的Keil說(shuō)明書(shū)譯文, 連接器是否自動(dòng)把?STACK定位在IDATA頂端?還是需要人工執行STACK連接命令之后才行?冷漠也有疑問(wèn)?不太清楚。
S
請你仔細看我的原話(huà),沒(méi)有理解就不要亂引用
我是說(shuō)KEIL默認的堆棧長(cháng)度是1字節<,可以改,只要編譯器能分配一個(gè)字節的空間,就不會(huì )報錯>,但其實(shí)所有沒(méi)有被編譯器使用的IDATA空間都是堆棧,當然中間的間隙不算
對自己在12樓的話(huà)解釋一下
關(guān)于棧頂的理解其實(shí)和LZ是一樣的,只是說(shuō)法稍微不同。
堆棧指針SP的范圍,最小叫棧底,最大叫棧頂。SP在棧底和棧頂之間活動(dòng)。所以本例中,棧頂是IDATA頂端0XFF,這么理解沒(méi)錯。
我12樓這么說(shuō),我是這么理解的
因為堆棧指針SP的值是棧頂的地址,所以SP活動(dòng),那么棧頂也跟著(zhù)活動(dòng)的。(SP指向棧頂)
棧頂的范圍:最小值即棧底,最大值即 最大棧頂值。
其實(shí)和LZ的意思是一樣的。
冷漠有另一觀(guān)點(diǎn):
C51對用戶(hù)來(lái)說(shuō)沒(méi)有SP的概念,你是C51用戶(hù)你不是編譯器作者,要么你說(shuō)自己只用匯編,那我們討論不在一個(gè)層次,一定注意不要以匯編的概念來(lái)理解C編 譯器,?STACK 就是編譯器生成的堆棧段,而且我認為這個(gè)?STACK 以上編譯器不可能分配其它數據段。所以從?STACK以上都是堆棧段,即使有很多不用的空間,也不可能被誰(shuí)占用,編譯器沒(méi)有讓誰(shuí)用。——這不是匯編語(yǔ)言編 程,程序員無(wú)法控制SP的。
評論