?

嵌入式軟件堆棧溢出的動態檢測方案設計*

2018-03-01 00:36,,,,
單片機與嵌入式系統應用 2018年2期
關鍵詞:服務程序堆棧使用量

,,,,

(1.齊魯工業大學(山東省科學院),濟南 250353;2.山東省科學院自動化研究所;3.山東省汽車電子技術重點實驗室)

引 言

面向特定應用的嵌入式系統一般會根據實際需求選擇規格適中的MCU,采用C語言進行軟件開發。在MCU的地址空間中,RAM是一段連續分配的線性空間,全局變量、堆(Heap)、堆棧(Stack)都分配在這段有限的線性空間內,根據實際需要,還可能把FLASH中一段代碼重定位到一段RAM空間內運行,以加快程序運行速度[1],提高系統實時性。

由于RAM資源有限,不可能為堆棧分配太大的尺寸,而且,作為一種靈活性很強的高級編程語言,C語言采用線性尋址方式訪問RAM空間,堆棧溢出時會繼續訪問臨近堆棧的RAM空間。堆棧尺寸設置過小、局部變量尺寸定義過大、中斷優先級設置不合理、中斷服務程序過長導致中斷嵌套、遞歸調用、函數調用層次過深等程序設計不當之處都可能導致堆棧溢出,改變臨近堆棧的RAM空間中的內容,從而造成程序運行異常[2],發生故障甚至導致重大事故。

1 方案設計

通過靜態分析方式確定堆??臻g的尺寸時,需要根據源程序中每個函數的局部變量大小確定每個函數的堆棧使用量[3],然后根據編譯器生成的函數調用列表為每個函數建立調用樹,檢查每棵調用樹,確定從樹根到樹葉的調用路徑的堆棧使用量,從中選出最大堆棧使用量,同時,還要仔細分析系統用到的所有中斷,確定中斷服務程序的堆棧使用量。但是,無法得知C標準庫函數以及大值整數的乘除、浮點運算等對應的運行庫函數的堆棧使用量,這種靜態分析方式對開發者的技術水平、對產品代碼的理解程度要求非常高,得到的數據并不完善,而且這種方式依賴于具體的應用和源程序實現方式,缺乏通用性。

本文設計了一種檢測嵌入式軟件堆棧溢出及使用量的方案[4],在不影響系統正常運行的情況下,在不受堆棧溢出影響的定時器中斷服務程序中,周期檢測堆棧使用量,通過控制LED提示堆棧溢出情況。設置了堆棧溢出緩沖區,隔離堆棧和全局變量分區,堆棧溢出后部分上下文信息被存放在堆棧溢出緩沖區中,將最大堆棧使用量和系統發生堆棧溢出后的堆棧溢出緩沖區數據存入非易失性存儲器。系統在實際環境中運行一段時間后,通過查看LED狀態以及讀取非易失性存儲器中的數據,便可以判斷堆棧使用情況,通過保存的溢出上下文數據可以分析程序異常位置,從而調整堆棧尺寸或者調整程序設計,以提高系統運行的穩定性。

2 軟件設計

2.1 RAM空間劃分

堆棧的生長方向為自上而下,即向著RAM地址減小的方向增長。如果把堆??臻g設置在RAM的底部,堆棧溢出時會訪問不存在的RAM空間,造成代碼跑飛,這時無法得到溢出時的上下文數據,也無法對后續的程序修改提供有用信息,所以,在劃分RAM空間時,需要將堆??臻g設置在RAM空間的頂部。在鏈接文件中,按照從頂部到底部的順序,將RAM空間劃分為堆棧區、堆棧溢出緩沖區和全局變量區,根據需要和MCU RAM空間尺寸,還可能設置有代碼重定位區[5]。具體劃分如圖1所示。

圖1 RAM空間劃分圖

在RAM頂部設置大小為STACK_SIZE的堆棧區,STACK_SIZE根據實際應用設置,留有一定的余量,同時受限于RAM資源,STACK_SIZE不能設置過大,棧底為堆棧區的最大地址,記為STACK_BOTTOM,設置為MCU RAM空間的最大地址;緊鄰堆棧區,設置尺寸為100字節大小的堆棧溢出緩沖區;緊鄰堆棧溢出緩沖區,設置尺寸為APP_RAM_SIZE的全局變量區,MCU的RAM尺寸記為RAM_SIZE。STACK_SIZE、APP_RAM_SIZE和RAM_SIZE的關系為:RAM_SIZE≥STACK_SIZE+100+APP_RAM_SIZE。

2.2 堆棧溢出緩沖區

堆棧溢出緩沖區位于堆棧和全局變量區之間,可以起到隔離堆棧和全局變量區的作用,當堆棧溢出時,如果溢出深度小于堆棧溢出緩沖區的尺寸,則不會影響全局變量,全局變量的變化也不會改變堆棧內容。

在堆棧溢出緩沖區中定義一個包含100個單字節元素的數組,記為Stack_overflow_buf[100],堆棧溢出時,該數組會存放一部分上下文數據,為后續的程序分析提供關鍵信息。

2.3 堆棧溢出檢測算法

系統運行期間,堆棧操作會改變堆棧區數據,堆棧溢出會改變Stack_overflow_buf數據,通過檢查堆棧區數據和Stack_overflow_buf,便可以得知系統對堆棧的實際消耗。堆棧溢出可能會改變程序計數器的數值,如果把堆棧檢測函數放在中斷服務程序之外的其它位置,程序可能無法運行堆棧檢測函數,而即使發生了堆棧溢出,中斷也會觸發MCU進入中斷服務程序,因此,將堆棧檢測函數放在定時器中斷服務程序中。

MCU上電初始化時,將堆棧指針SP初始化為STACK_BOTTOM,堆棧區數據和數組Stack_overflow_buf全部初始化為0x55,最大堆棧使用量記為Stack_size_max,初始化為0,然后開啟一個周期為50 ms的定時器。在定時器中斷服務程序中,讀取堆棧溢出緩沖區和堆棧區的數據,判斷堆棧使用情況。

具體方法為:

讀取次數記為Read_times,初始化為0,以堆棧溢出緩沖區初始地址為首地址,以堆棧棧底為末地址,循環讀取各個RAM地址上的數據,如果讀取到的數據等于0x55,讀取地址加1,讀取次數加1,如果讀取到的數據不等于0x55,跳出RAM讀取循環。

根據當前最大堆棧使用量=STACK_SIZE+100-Read_times,如果當前最大堆棧使用量大于Stack_size_max,將當前最大堆棧使用量賦值給Stack_size_max,存入非易失性存儲器,如果Stack_size_max小于或等于STACK_SIZE,不再進行處理,等待下一次定時中斷。否則,判斷為堆棧溢出,將數組Stack_overflow_buf的數據作為溢出上下文,存入非易失性存儲器;進一步根據Stack_size_max判斷是深度溢出還是淺度溢出,如果Stack_size_max小于(STACK_ZIZE + 100),此時的堆棧溢出不會影響全局變量區,不會造成系統運行異常,從而點亮LED進行提示。如果Stack_size_max等于(STACK_ZIZE + 100),此時的堆棧溢出會影響全局變量區,造成系統運行異常,閃爍LED燈進行提示。此時,通過專用設備可以讀取存儲在非易失性存儲器中的最大堆棧使用量和Stack_overflow_buf。根據Stack_overflow_buf數據判斷堆棧溢出位置,修改程序設計或者增加堆??臻g的大小。 堆棧溢出檢測算法流程圖如圖2所示。(說明:定時器中斷判斷分支的“N”分支與本文內容無關,所以未列出。)

圖2 堆棧溢出檢測算法流程圖

結 語

[1] 高源,羅秋鳳.基于DSP28335程序移植方法的研究與實現[J].電子測量技術,2013,36(3):84-88.

[2] 北京空間飛行器總體設計部.一種適用于多任務軟件進程堆棧使用深度檢測的方法:中國,201610080939.2 [P].2016-2-14.

[3] 張西超,郭向英.一種用于分析MCS-51目標碼堆棧深度的方法[J].空間控制技術與應用,2010,36(2):47-50

[4] 山東省科學院自動化研究所.嵌入式軟件堆棧溢出檢測方法和裝置:中國,201710997905.5[P].2017-10-11.

[5] 山東省科學院自動化研究所.CAN報文濾波解析方法、系統及電子控制單元:中國,201710743658.5 [P].2017-8-25.

馬建輝(工程師),研究方向為嵌入式與汽車電子。

猜你喜歡
服務程序堆棧使用量
基于行為監測的嵌入式操作系統堆棧溢出測試*
減少#1爐再熱器減溫水使用量
“以蟲吃蟲”這家大棚農藥使用量減少30%
SylixOS系統的中斷嵌套機制研究與實現
基于C#的進程守護程序的設計
UDP穿透NAT技術實現數據喚醒車聯網T-Box設備的方案
基于堆棧自編碼降維的武器裝備體系效能預測
В Китае снизился объем использования пластиковых пакетов 中國塑料袋使用量減少
未來汽車的塑料使用量將呈倍數增長
水利工程施工監理服務程序及質量控制
91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合