<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 51堆棧的安全(精確)設(shè)置

          51堆棧的安全(精確)設(shè)置

          作者: 時間:2016-11-28 來源:網(wǎng)絡(luò) 收藏
          幾個問題:
          1、編譯器、連接器把堆棧段定位在IDATA內(nèi)所有段的最后面,也即內(nèi)存IDATA高端;
          2、中斷堆棧被定位在堆棧段內(nèi)的最后面,即IDATA最頂端;所以堆棧段的安全余量設(shè)置,實際上是中斷堆棧深度的配置。
          3、如果不考慮系統(tǒng)堆棧的安全余量設(shè)置,一個沒有二級中斷嵌套的一級中斷堆棧深度應(yīng)該是13字節(jié)。——為什么?
          4、系統(tǒng)中斷的安全余量配置應(yīng)該是……字節(jié)。——為什么?

          下面詳細(xì)說明:

          1、整個51內(nèi)存256字節(jié)。C51首先分配全局靜態(tài)變量在IDATA低端,接著分配的是項目中所有函數(shù)的參數(shù)和局部變量共享覆蓋區(qū)——也屬于全局靜態(tài)變量區(qū)(段)。(有沒有動態(tài)數(shù)組區(qū)段冷漠不知道也不關(guān)心,)然后就是系統(tǒng)堆棧段,其棧底指針?STACK——由C51自動生成,棧頂應(yīng)該是IDATA頂端——0xFF。系統(tǒng)堆棧深度=0xFF-(?STACK)。
          如果項目中含有匯編模塊, 那么系統(tǒng)堆棧?STACK中還包含匯編模塊私有堆棧STACK(指針指向)如果項目中包含有reentrant 重入函數(shù) foo,那么系統(tǒng)堆棧中還包含有每個foo所屬的私有模擬堆棧simulatedstack;它也是C51為每個reentrant 函數(shù)自動分配的。對于interrupt 屬性函數(shù),C51為其分配中斷函數(shù)私有堆棧……還有硬件堆棧hardwarestack 的概念(函數(shù)調(diào)用CALL或者中斷發(fā)生時由硬件自動壓入PC的堆棧。)
          所以,一個系統(tǒng)堆棧段內(nèi)分配了很多私有堆棧,所謂私有,應(yīng)該是操作系統(tǒng)概念,用在這里是為了與系統(tǒng)堆棧?STACK 區(qū)分概念,例如,當(dāng)一個中斷事件發(fā)生時,它所打斷的后臺程序F1 所正在使用的堆棧,是不可能與中斷函數(shù)堆棧共享的。——2者堆棧都是私有的。
          由于中斷函數(shù)具有最高優(yōu)先權(quán),且堆棧獨立,所以我說中斷函數(shù)堆棧必然處在所有其它私有STACK之上,是IDATA最頂端的堆棧;——安全余量必是在中斷堆棧之上分配。

          ……Cx51編譯器會(自動——冷漠注釋)產(chǎn)生一個?STACK的堆棧段,該段將被自動定位到IDATA空間的頂部。……一般不需要特別指定?STACK 的位置,對于具有幾個堆棧的匯編程序才需要采用STACK命令。需要注意的是,重新定位?STACK 段必須非常小心,因為可能會破壞 DATA 或 IDATA 空間的變量而導(dǎo)致程序無**常運行。

          ——摘自《Keil Cx51 V7.0單片機高級語言編程與uVision2應(yīng)用實踐》 徐愛鈞編著 P640

          冷漠同學(xué)啊, 引用就引用吧, 干么斷章取義,還夾雜私貨, 這樣不好嘛。

          1)中斷堆棧最大可能深度是15(2+5+8)字節(jié), 不是 13。原因已經(jīng)給出, 不再重復(fù)。

          2)8051 運行時有只有一個統(tǒng)一stack, 不存在 中斷堆棧 以及 非中斷堆棧, os 或程序人為操縱stack 另當(dāng)別論。

          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)一定位。目標(biāo)代碼*****運行時*******,只有一個stack. 所有的函數(shù)調(diào)用, 中斷斷點, 以及中斷register保護都在一個 stack 里。這是最基本的****常識***問題!?。?! os 的人為分割切換 stack 完全是另一個概念。

          請教 冷漠大師:

          您所言的“后臺堆棧”,實際上是C語言中的軟堆棧,負(fù)責(zé)分配在全局靜態(tài)變量空間共享覆蓋區(qū),其長度為每個獨立的后臺函數(shù)的私有堆棧之和!
          您所言的“前臺堆棧”,實際是51單片機中真正的硬件堆棧,負(fù)責(zé)中斷響應(yīng)需要保護的變量,子函數(shù)調(diào)用等硬性的壓棧出棧操作!

          C語言的運行是依靠這一軟一硬兩個堆棧協(xié)調(diào)工作,您所言的:一高(端)一低(端),一小一大,一前(臺)一后(臺)。就是指這一軟一硬兩個堆棧。

          不知俺理解的對不對?

          提一個問題:什么是堆棧?

          如果,堆棧是指硬件堆棧,那個由堆棧指針SP所控制的,那當(dāng)然只有一個堆棧,沒有什么私有的堆棧,包括中斷等,都是往這個堆棧上放,

          如果自己在函數(shù)里(操作系統(tǒng)也不過是一些函數(shù),一些公用的函數(shù)集而已)定義一個堆棧,那個堆棧就不好說,那叫軟堆棧。

          一個處理系統(tǒng)有且只有一個當(dāng)前堆棧,就是有SP寄存器控制的那個。不管是中斷發(fā)生還是函數(shù)調(diào)用,都是用這個SP定位。其余什么私有堆棧不過是程序修改SP而實現(xiàn)的。
          堆棧的深度是不宜精確設(shè)置的,除非你的程序很簡單,或根本就沒有中斷嵌套,這樣你可以很容易計算出系統(tǒng)可能最大堆棧。不然沒什么好說的,將必要的內(nèi)存設(shè)置好,其余的統(tǒng)統(tǒng)留給堆棧(反正閑著也是閑著)。

          特地說明一點:
          “reentrant"的 "simulated stack" 只是為了模擬通過 stack 傳遞參數(shù)(這是大多數(shù)c 編譯器的做法)以實現(xiàn)重入,實際實現(xiàn)上有點復(fù)雜,是Rn寄存器再加上一個“simulated stack" 數(shù)據(jù)區(qū)(具體情況可以看看反匯編)。這個“simulated stack" 自頂向下, 參數(shù)通過 r0, r1或 dptr 存取, 是一個特別數(shù)據(jù)區(qū), 不是一個真正的 stack,與真正的硬件自動 stack (通過 sp push/pop) 無關(guān).

          具體沒看過編譯手冊,不過對于這句有些疑問:
          其棧底指針?STACK——由C51自動生成,棧頂應(yīng)該是IDATA頂端——0xFF

          51堆棧是向上生長型,剛開始棧頂應(yīng)該在棧底那里,每次PUSH,往上加,直到最大0XFF.但是你這里說棧頂應(yīng)該在IDATA的頂端--OXFF,應(yīng)該不對。

          負(fù)責(zé)分配在全局靜態(tài)變量空間共享覆蓋區(qū),其長度為每個獨立的后臺函數(shù)的私有堆棧之和!

          “軟堆棧”的提法非常贊同。絕不是一般人所能理解到如此深刻的。其它先不多說,——我還沒講到。但是上面紅線部分我有異議:就像后臺所有非重入函數(shù)的參數(shù)傳遞和局部變量被分配在共享覆蓋區(qū)一樣,其長度應(yīng)該是占用內(nèi)存字節(jié)數(shù)最多的那個函數(shù)所占有的區(qū)域,其它函數(shù)分時共享這個區(qū)域。——而不是所有之和。這才是共享、覆蓋的操作系統(tǒng)內(nèi)存管理的方法和意義吧?
          還有,私有堆棧之和可能忽略了一件事,所有私有堆棧都是動態(tài)意義的,當(dāng)這個函數(shù)未被調(diào)用時,它是不活動的,所以它的私有堆棧也不存在(長度等于零),這也是覆蓋與共享的前提吧?
          我表達(dá)的不好,感謝老許是真正懂的、真正討論問題的人。

          同意12樓,說的太好了。這里確實不好得出唯一結(jié)論;記得ayb_ice詳細(xì)論證過,堆棧長度開始為什么是1字節(jié)。建議去看看他的帖子。我不能確定唯一結(jié)論的理由:
          1、?STACK是由編譯器自動生成的系統(tǒng)堆棧段,——所有含有PUSH / POP指令操作的函數(shù),都在這個系統(tǒng)堆棧段里享有自己的連續(xù)堆??臻g(注意是動態(tài)的。)?STACK所指向的系統(tǒng)堆棧段被分配在系統(tǒng)所有其它RAM段的最后面。?STACK肯定是始終指向系統(tǒng)堆棧棧底,連接定位之后就不可移動的;

          2、“最后面的”后面還能安排有東西么?冷漠認(rèn)為編譯器不可能出爾反爾,所以認(rèn)為沒有了,所以冷漠說棧頂是IDATA的頂。12樓可以說棧頂是移動的,移動上限是IDATA頂端。冷漠堅決同意。
          當(dāng)然通過設(shè)置可以讓IDATA的頂不等于0xFF;例如等于0xEE什么的。這是冷漠說話不嚴(yán)格。

          ?STACK的定位是連接器確定的,和編譯器無關(guān)。LZ已經(jīng)舉了書上的Keil說明書譯文, 連接器是否自動把?STACK定位在IDATA頂端?還是需要人工執(zhí)行STACK連接命令之后才行?冷漠也有疑問?不太清楚。

          S
          請你仔細(xì)看我的原話,沒有理解就不要亂引用
          我是說KEIL默認(rèn)的堆棧長度是1字節(jié)<,可以改,只要編譯器能分配一個字節(jié)的空間,就不會報錯>,但其實所有沒有被編譯器使用的IDATA空間都是堆棧,當(dāng)然中間的間隙不算

          對自己在12樓的話解釋一下
          關(guān)于棧頂?shù)睦斫馄鋵嵑蚅Z是一樣的,只是說法稍微不同。
          堆棧指針SP的范圍,最小叫棧底,最大叫棧頂。SP在棧底和棧頂之間活動。所以本例中,棧頂是IDATA頂端0XFF,這么理解沒錯。

          我12樓這么說,我是這么理解的
          因為堆棧指針SP的值是棧頂?shù)牡刂罚許P活動,那么棧頂也跟著活動的。(SP指向棧頂)
          棧頂?shù)姆秶鹤钚≈导礂5?,最大值?最大棧頂值。

          其實和LZ的意思是一樣的。

          冷漠有另一觀點:

          C51對用戶來說沒有SP的概念,你是C51用戶你不是編譯器作者,要么你說自己只用匯編,那我們討論不在一個層次,一定注意不要以匯編的概念來理解C編 譯器,?STACK 就是編譯器生成的堆棧段,而且我認(rèn)為這個?STACK 以上編譯器不可能分配其它數(shù)據(jù)段。所以從?STACK以上都是堆棧段,即使有很多不用的空間,也不可能被誰占用,編譯器沒有讓誰用。——這不是匯編語言編 程,程序員無法控制SP的。冷漠才不管它SP在哪。愿意在哪在哪,編譯器一定比我做的高明。是吧。小問題,無所謂對錯。都不影響使用C51。

          上一頁 1 2 下一頁

          關(guān)鍵詞: 51堆棧安全設(shè)

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();