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