新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 實時嵌入式系統軟件調試問題分析

        實時嵌入式系統軟件調試問題分析

        作者: 時間:2010-09-29 來源:網絡 收藏

          內存和寄存器的數據訛誤

          大多數的都采用了平面化的內存模式,也并沒有內存管理單元(MMU),于是沒有硬件支持的內存保護機制。即使采用能提供這種功能的處理器,也需要由開發商來實現對某些內存區域的保護。進程和線程將對其它進程和線程的內存空間有完全的訪問權限。這可能會造成下面所描述的、各種類型的內存訛誤

          堆棧溢出

          運行時堆棧是在函數調用進程中所使用的一種暫存空間,用于存儲局部變量。硬件寄存器指針(SP)將跟蹤堆棧指針的地址。如果你在高級的語言中編程,如C語音,則編譯器所生成的代碼將使用與C語言運行時間模型相一致的堆棧。運行時間模式定義了變量是如何存儲在堆棧中的以及編譯器將如何使用堆棧。局部的變量被放置在當前的堆棧中。下面給出的例子描述了在堆棧上采用的某些關鍵性的內存。

          

          當堆棧指針超出了其所指定的邊界時,就會出現堆棧溢出。這將造成內存的訛誤,并最終造成的失效。在上述的實例中,如果總的堆棧內存區不足以容納所有的局部變量,堆棧溢出就會發生。

          的一個技巧就是,如果你擔心溢出,一個好的做法,就是將堆棧安排在內存邊界上,這樣,如果在過程中出現了溢出,則仿真器將觸發一個硬件異常提示。

          開發商可以采用的一個技巧是,如果你擔心堆棧的溢出,你就應當考慮把它放在有效的內存的邊界上。這樣,當堆棧溢出時,設備將報告硬件異常,而不是造成其它內存空間的訛誤。

          在獨立運行的應用中,運行時間堆??赡芫鸵呀泬蛴?。然而,在使用任何一種操作時,每個線程和過程都將有自己的堆棧??紤]到性能方面的原因,大多數操作系統的堆棧尺寸都是事先確定的,無法在運行中動態擴展。這意味著,如果針對特定的線程/進程所選用的堆棧尺寸不恰當的話,堆棧溢出就會發生。

          如果應用大量使用局部變量(如陣列和大的結構),則將不得不按比例為其分配堆棧的空間。人們可以利用malloc() 來分配內存,或者將其設置為靜態的全局變量,具體是何種方法,則取決于實際應用。

          有些操作系統可能會提供功能,例如保護位,以形成對堆棧溢出的防護。這些操作系統要么記錄關于堆棧溢出的錯誤信息,要么提交一個異常報告,以便動態地增加堆棧。最起碼當前的大多數實時操作系統都能報告堆棧以及已經被線程和進程所采用的堆棧的情況。

          在任何中斷驅動的系統中,堆棧的分配方式都必須考慮到中斷服務例程所采用的空間。如果中斷例程的設計目標是使用當前的執行對象棧,則在這種情況下,每一個線程或進程所擁有的最小的堆棧尺寸都應大于或者等于執行對象所要求的堆棧尺寸加上所有中斷例程累積起來所需要的最大的堆棧尺寸。

          系統開發商必須掌握各種應用鏈接庫。例如,第三方的庫可能會認定堆棧上為其提供了空間。

          中斷服務例程代碼編寫時所出的

          在嵌入式系統中,一般情況下,出于性能方面的考慮,中斷服務例程是以匯編形式編寫的。中斷本質上是異步的,在應用執行中的任何時刻都有可能出現。匯編層次上的中斷例程最常見的,是寄存器的訛誤。在中斷服務例程中所采用的寄存器所存儲的數據,在寄存器被使用之前都必須被保存,而在從中斷服務例程返回之前,這些數據將被恢復。開發商必須了解狀態寄存器的情況,而任何一種ALU的操作都會改變其狀態。在這種情形中,ISR應該保存其狀態并進行恢復,仿佛它是一個已被使用的寄存器一般。

          如果中斷例程是用C語言編寫 的,它們的開發也是為了使用當前的堆棧,則開發商就應該針對堆棧溢出情況進行防護,即每個線程都應該擁有足夠多的堆棧,來滿足中斷或者嵌套的中斷堆棧的要求。最好的做法,就是讓中斷例程的規模盡可能小,推遲處理過程,交給一個線程或者優先級較低的中斷。在開發過程中,開發商可以在中斷的開始和結束部分添加診斷功能,對基礎的架構中的寄存器的狀態進行比較。

          中斷嵌套可以讓一個高優先級的中斷搶先于低優先級的中斷例程執行。開發商應該考慮到堆棧要求的峰值,并為其分配充足的空間(考慮最差的情況,即你的系統中的每一個中斷都被一個優先級更高的中斷所搶先)。

          而操作內存映射寄存器(MMR)時,人們常常采用在線匯編以改善性能。例如,你在屏蔽中斷時,可能希望直接設定中斷屏蔽寄存器(IMASK)而不是執行RTOS所提供的應用編程接口(API)。例如原子增加或減少操作常常是用匯編語言編寫的。在C函數中,這些宏匯編可能會被調用,在這種情況下,編譯器可能不了解在宏匯編中所使用的寄存器。因此這會導致寄存器的訛誤。有些編譯器具有匯編的擴展版,可以將關于這些函數的更多的信息傳遞給編譯器,例如已被使用的寄存器、代碼在內存中的位置等等。這將使得編譯器可以生成恰當的代碼。

          有時,某些函數是以匯編語言編寫的,將被C函數所調用。如果匯編代碼并未按照C函數運行時間調用規范來編寫,即按照編譯器所要求的那樣進行,則會導致參數傳遞(argument passing)無效和訛誤。例如,C函數運行時間模型可以規定前兩個參量必須通過寄存器R0和R1來傳遞,則匯編的實現方式就必須按照這種語法來編寫。在另一種情況下,運行時間模型可能需要存儲堆棧上的函數的返回地址。如果匯編的實現方法并不符合運行時間模型,則它可能會攪亂某些 寄存器,并帶來系統的故障。如果開發商使用混合模式的語言來避免這種類型的問題的話,開發商就必須清楚運行時間模型。

          編譯器:

          編譯器的優化,即使實現了邏輯上的正確性,有時也仍然會造成故障。采用低水平的設備驅動器時,這一問題特別關鍵。重排指令是實現更高性能的常用方法,因為處理器常常支持單個周期內執行多條指令。因此,編譯器將試圖調度指令,使得所有的指令時間片都得到充分的利用,即使這意味著在寄存器使用前很久就載入數據,或者在數值被計算完畢后很久,也讓內存保持載入的數據。請看附圖,其中描述了這種內存的移動是如何發生的。

          

        linux操作系統文章專題:linux操作系統詳解(linux不再難懂)


        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 滨州市| 睢宁县| 中卫市| 满洲里市| 黄浦区| 庆安县| 荥阳市| 榕江县| 乌什县| 连南| 静乐县| 湖州市| 卢氏县| 大悟县| 黄平县| 通许县| 林西县| 新巴尔虎左旗| 余庆县| 望江县| 滦平县| 万源市| 汶川县| 五大连池市| 昔阳县| 广南县| 海宁市| 新津县| 锡林郭勒盟| 微博| 新泰市| 昌黎县| 平昌县| 尉犁县| 萍乡市| 卫辉市| 仁布县| 石景山区| 无为县| 牡丹江市| 德安县|