1 現象
當執行一段程序時,發生錯誤,並報”illegal instruction”錯
typedef void(*FUNC)(void);int main(void)
{ const static unsigned char insn[4] = { 0xff, 0xff, 0xff, 0xff }; FUNC function = (FUNC) insn;
function();
}
編譯執行之:
$ gcc -o sigill illegal_instruction.c
$ ./sigill
Illegal instruction
2 關於“illegal instruction”
illegal instruction,即SIGILL, 是POSIX標準中提供的一類錯誤。 從名字上看,SIGILL是啓動的某個進程中的某一句不能被CPU識別成正確的指令。 此類錯誤是由操作系統發送給進程的,在進程試圖執行一些形式錯誤、未知或者特權指令時操作系統會使用SIGILL信號終止程序。 SIGILL對應的常數是4.
3 造成SIGILL的原因
3.1 將不正確的數據寫入代碼段
進程在代碼段中的數據是要被作爲一個指令執行的。 若不小心覆蓋了已有的代碼段,可能會得到錯誤格式的指令。 這種錯誤尤其在Just-In-Time即時編譯器中最可能出現。
同樣,如果不小心覆蓋了棧上活躍記錄中的返回地址,程序就可能根據這個錯誤地址,執行沒有意義的內存中的數據,進而操作。
進一步可以認爲,任何導致數據錯誤的問題都可能帶來illegal instruction問題。比如硬盤發生故障。
3.2 指令集的演進
比如SIMD指令,自從奔騰4開始有MMX,X86的芯片就開始不停的增加和拓寬SIMD支持,SSE、SSE2、SSE3、SSE42、AVX、AVX2。 默認情況下,很多編譯器都在O2或者O3中開了自動向量化,這就導致很多在新體系結構中編譯的可執行程序,在老機器上運行時會有illegal instruction問題。
3.3 工具鏈bug
對於普通C語言通過編譯器生成的可執行程序。一般都已經通過嚴格的測試,不會隨便發生這種問題。 所以如果你遇到這種錯,並且試過了靜態鏈,而且程序中沒有嵌入式彙編,基本可以斷定是工具鏈出了問題。 編譯器?彙編器或者鏈接器。
3.4訪存對齊或浮點數格式問題
根據Heiher的經驗,請注意出現錯誤的指令可能和訪存地址指令有關。 另外,浮點數的格式是否符合IEEE的標準也可能會有影響。
4 錯誤排查指南
程序中有沒有特權指令、或者訪問特權寄存器
有沒有將在較新CPU上編譯得到的可執行文件拿到老CPU上運行
程序中有沒有嵌入式彙編,先檢查。
一般編譯器很少會生成有這種問題的代碼
X86平臺上要尤其注意64位彙編指令和32位彙編指令的混用問題
程序有在進程代碼段空間寫數據的機會嗎?
棧操作夠安全嗎?
注意程序的ABI是否正確
尤其是動態鏈和靜態鏈是否處理的正確,儘量避免動態鏈的可執行文件調用錯誤庫的問題(ARM的EABI,MIPS的N32/O32/N64都很可能出這種問題)
用的工具鏈靠譜嗎?
5 舉例
wifimanager使用中,wifi名設置中文字符大於2個字,調用wifid -t查看狀態時將wifi_daemon守護線程殺死.
此爲異常退出,分析發現在拷貝ssid時出現目的地址長度不對.
strncpy(s->ssid,staInfo->ssid,strlen(staInfo->ssid)); 默認s->ssid的結構體長度設置太小了
6 參考
http://en.wikipedia.org/wiki/SIGILL
http://www.slac.stanford.edu/BFROOT/www/Computing/Environment/Tools/Batch/exitcode.html
http://stackoverflow.com/questions/6934592/is-this-a-valid-x86-assembly-instruction
http://blog.csdn.net/qiaoliang328/article/details/4866367
http://www.justlinux.com/forum/archive/index.php/t-117434.html