2016-02-01 34 views
0

有什麼方法檢查或防止堆棧區域超出有限內存(RAM/ROM)嵌入式系統中的RAM數據(.data或.bss)區域包括微控制器?有工具可以做到這一點,但是它們在IAR中帶有非常昂貴的許可證費用,例如C-STAT和C-RUN。在運行期間檢測堆棧區域的方式不與RAM區域重疊

+1

堆棧分配在RAM中,所以我把它指向'.data'和'.bss'段? – Lundin

+0

是的,這是正確的! – Raulp

回答

3

無需外部工具即可查看和重新映射內存佈局。您正在使用的編譯器/鏈接器應該提供這樣做的手段。如何做到這一點當然是非常系統特定的。

您所做的是打開系統特定的鏈接器文件,其中所有內存段已預先定義爲給定微控制器的默認值。您應該在其中列出各種RAM段,事實上的標準名稱是:.stack.data.bss.heap

每個這樣的段將具有指定的地址範圍。更改地址,您將移動細分。但是,這些鏈接文件通常會有一些模糊的語法,您在觸摸任何內容之前需要先學習。如果您(非)幸運的話,它會使用GNU鏈接器腳本,這是一個有據可查的,但相當複雜的標準。

也可能有一些製造商提供的啓動代碼來設置堆棧指針。除了調整鏈接文件之外,您可能還必須手動修改該代碼。

關於堆棧:您需要檢查CPU核心手冊,並查看堆棧指針是否在給定系統上向上或向下移動。最常見的是向下,但存在替代方案。您應該確保在堆棧增長的方向上,沒有其他可以在堆棧溢出時覆蓋的讀/寫數據段。理想情況下,堆棧應該溢出到非映射內存中,訪問會導致CPU硬件中斷/異常。

這是描述如何做到這一點的article

1

在沒有必要的硬件支持的小型微型計算機中,一個非常簡單的方法是定期執行任務(在多任務器或通過定時中斷的情況下)檢查必須的「閾值」RAM地址已經初始化爲一些'魔術'模式,如0xAA55

一旦週期性任務看到這個內存地址改變的內容,就有問題了!

+0

這隻檢查堆棧溢出。它不檢查堆棧損壞 – user3629249

+0

標題說:「檢測堆棧區域的方式在運行時不與RAM區域重疊」! – tonypdmtr

1

在資源有限的微控制器,它始終是防止堆棧溢出經由簡單的內存使用情況的優化是一個好主意:

  • 通過在非易失性的(例如,閃存),用於存儲只讀變量降低整體RAM使用記憶。一個好的目標是代碼中的常量字符串,例如,在printf()格式字符串上使用的字符串。這可以釋放大量的內存,使堆棧增長。檢查你的編譯器文檔,瞭解如何在Flash中分配這些變量。
  • 避免遞歸調用 - 它們在資源受限或安全關鍵型系統中不是一個好主意,因爲您幾乎無法控制堆棧的增長。
  • 避免在函數調用中按值傳遞大型參數 - 儘可能將其作爲const引用傳遞(例如,對於結構體或類)。
  • 儘量減少不必要的局部變量的使用。例如,特別要查看大型的,比如本地緩衝區。通常,您可以找到方法來刪除它們,或者使用共享資源,而不會影響代碼。
+0

可以本地更改爲全局或靜態?零初始化會好還是未初始化更好?但我恐怕他們會加起來的RAM大小.Isnt? – Raulp

+0

我認爲改變爲靜態並不是很有幫助,因爲你只會在可重入函數中節省內存,但是你可能不想在靜態變量上使用靜態變量。但是,如果您在不使用任何花哨的工具的情況下分析代碼(例如,只是檢查.map文件),預測內存使用情況會更容易。你可以使用共享的全局變量,但這不是很好的編碼習慣,並且可能危害模塊性,所以我只會考慮使用太多內存的地方。但它確實取決於程序的複雜性。如果很簡單,使用幾個全局變量通常是可以的。 –

+0

變量初始化或未初始化它沒有任何區別。在使用全局變量(我的意思是緩衝區和大型的類/記錄)方面,你可能能夠以優雅的方式傳遞引用,而不會影響代碼的質量和模塊性。 –