標籤:linux mismatch section
by falcon [email protected] of TinyLab.org
2014/01/22
Section Mismatch簡介
Section Mismatch是非常嚴重的Bug,可能會導致無法預測的記憶體訪問問題,建議謹慎對待,如果添加的驅動中有類似Warning,可能需要密切關注並解決掉。
下面就該問題的檢測、原因、解決思路以及最新前沿進行分析。
Section Mismatch的檢測
CONFIG_DEBUG_SECTION_MISMATCH=y
開啟上述選項,核心就會調用modpost檢測類似問題。
Section Mismatch的原因
Linux為了減少不必要的記憶體消耗,對於一些僅僅在核心初始化時使用的資源(包括函數和變數等),會放在init sections中,這些init sections會在核心初始化完成以後被核心Free掉。除此之外,考慮到不同模組或者子系統的差異,它們的代碼和資料也會放在各自的Section中,交叉的引用也可能出現潛在的問題。
如果一個Section引用了另外一個Section中的變數,就會出現Section Mismatch警告。如果是一個運行時函數引用了一個Init Section段中的函數,那麼問題就出現了。
當Linux核心啟動完成後,Init Section佔用的記憶體已經被Free掉,如果這部分記憶體被其他的裝置申請,寫進了不可預知的內容,那麼系統就會存在不可預知的風險,也許有些時候會很幸運,這部分記憶體從來都沒有被其他裝置引用,所以,即使編譯時間看到了Warning,系統也沒有崩潰,但是炸彈放在枕頭邊,很危險,早點搬走為好。
Section Mismatch的解決
有幾種情況:
- 如果運行時函數引用了Init Section中的函數或者變數
如果該運行時函數是必須要在運行時用到的,不能放到Init Section中,那麼就把Init Section中的函數的__init*標記去掉,否則給前者加上相應的Init聲明。
相關的init標記請參考:include/linux/init.h
- 如果不同的Section之間存在交叉引用,這個交叉引用是安全的,則用
__ref標記讓Section Mismatch Detector(modpost)忽略相關檢查
比如在cpu hotplug中,__cpuinit不會放在Init section中,在運行時訪問是安全的,如果有一個外部函數(無__cpuinit標記)訪問了用__cpuinit標記的函數,這個時候就存在交叉引用。因為這種訪問是安全的,所以可以讓核心忽略對它的檢測,用__ref標記該函數即可。
Section Mismatch的近況
在最新的ARM核心中,引入了一個智能檢測,該檢測是針對Free掉的記憶體被運行時函數訪問的情況,前面的分析提到類似的情況會導致無法預測的風險,而該智能檢測則會明確地報告出具體的問題。
該檢測的原理是把所有Init Section的記憶體地區在核心初始化時把這些記憶體地區初始化為0xe7fddef0 (an undefined instruction (ARM) or a branch to an undefined instruction (Thumb)),如果運行時函數非法訪問到了這些地區,會觸發一個undef instruction的異常並列印相應的回調,從而輔助開發人員更快地解決相關問題。
當然,這並不意味著我們不需要解決編譯時間的Warning,把問題Delay到運行時解決是更耗費精力的,應該在編碼或者編譯等早期開發過程中就解決掉,這樣會提高開發效率,這個思路對其他的問題同樣適用。
這部分的代碼請參考:arch/arm/mm/init.c: poison_init_mem()
Linux核心Section Mismatch詳解