2012-04-27 42 views
20

在運行程序集時我寫了Illegal instruction錯誤。有沒有辦法知道哪個指令導致了錯誤,沒有進行調試,因爲我運行的機器沒有調試器或任何開發系統。換句話說,我在一臺機器上編譯並運行另一臺機器。我無法在我編譯的機器上測試我的程序,因爲它們不支持SSE4.2。儘管如此,我正在運行該程序的機器確實支持SSE4.2指令。在沒有調試的情況下查找哪個彙編指令導致非法指令錯誤

我想這可能是因爲我需要告訴彙編程序(YASM)識別SSE4.2指令,就像我們通過傳遞它的-msse4.2標誌來處理gcc一樣。或者你認爲它不是原因?任何想法如何告訴YASM識別SSE4.2指令?

也許我應該捕獲SIGILL信號,然後對SA_SIGINFO進行解碼,看看程序做了什麼樣的非法操作。

+1

YASM確實承認SSE4.2指令,所以這不是問題。你確定你的機器支持SSE4.2嗎?它究竟是什麼硬件?你可以在模擬器中運行程序,valgrind(支持glibc和gcc中使用的SSE4.2的子集)可能會起作用。 – hirschhornsalz 2012-04-28 10:04:27

回答

27

實際上,您經常會得到一個非法的指令錯誤,不是因爲您的程序包含非法操作碼,而是因爲您的程序中存在一個錯誤(例如,緩衝區溢出),導致您的程序跳轉到一個隨機地址中,代碼,但不在操作碼的開頭。

3

那麼......您當然可以插入跟蹤打印輸出,這樣您就可以快速排除大部分代碼。完成後,運行例如

$ objdump --disassemble my-crashing-program | less 

然後跳轉到例如你知道的功能導致錯誤,並閱讀代碼,尋找任何看起來很奇怪的東西。

我不完全確定objdump如何顯示非法指令,但他們應該脫穎而出。

4

對於手寫彙編,我會懷疑堆棧管理問題導致無法返回。編寫一個調試打印輸出例程,保存每個寄存器並在每個函數的頂部插入一個調用。

然後你會看到你走多遠......

(順便說一句,寫機器代碼時良好的編輯器和彙編的宏語法有很好的理解就是救星。)

+0

我懷疑彙編程序要求我明確指定我正在使用SSE4.2指令,就像gcc需要傳遞-msse4.2標誌一樣。 – pythonic 2012-04-27 16:24:32

+2

但是,在彙編器中啓用指令只會改變允許的語法。我想,這不是誘捕和誘捕的區別。 – DigitalRoss 2012-04-27 16:28:58

+0

@ user1018562否。如果彙編器遇到目標體系結構不允許的指令,它將會出錯 - 但僅在編譯期間。如果在運行時存在錯誤,但在編譯期間不存在,則情況正好相反 - 彙編器發出指令,目標架構無法理解。所以如果有的話,你需要告訴編譯器不要發出SSE指令。 – hirschhornsalz 2012-04-28 10:07:47

11

如果您可以啓用在該系統上運行核心轉儲,運行該程序,讓它崩潰,然後將核心轉儲從目標機器上拖到您的開發機器上,並將其加載到構建用於調試目標體系結構的GDB中 - 它應該準確告訴您發生崩潰的位置。只需使用GDB的core命令將核心文件加載到調試器中即可。

  • 要啓用核心轉儲目標:

    ulimit -c unlimited 
    
  • 僞文件控制如何核心文件將被命名爲(貓這些看到當前配置,寫信給他們改變配置):

    /proc/sys/kernel/core_pattern 
    /proc/sys/kernel/core_uses_pid 
    

在我的系統,一旦核心轉儲被啓用,一個崩潰程序將令狀e工作目錄中簡單命名爲「核心」的文件。這對於你的目的來說可能已經足夠了,但是改變核心轉儲文件的命名方式可以讓你保留核心轉儲的歷史記錄(如果這是必要的話)。

+0

Linux操作系統我已經使用了所有的核心,稱爲core。$ PID。 – 2012-04-30 15:45:42

+0

@Warren:我的Ubuntu盒子(以及我們擁有的嵌入式版本)默認情況下出於某種原因被命名爲「core」。 – 2012-04-30 15:58:01

15

最近因爲132退出狀態碼(128 + 4:程序被信號+非法指令信號中斷)而遇到了崩潰。以下是我如何找出導致崩潰的指令。

首先,我啓用核心轉儲:

$ ulimit -c unlimited 

有趣的是,我在那裏運行的二進制文件夾包含一個名爲core文件夾。我不得不告訴Linux下的PID添加到核心轉儲:

$ sudo sysctl -w kernel.core_uses_pid=1 

然後我運行了一個程序,有一個名爲core.23650核心。我用gdb加載了二進制文件和核心文件。

$ gdb program core.23650 

一旦我到GDB,它顯示了以下信息:

Program terminated with signal SIGILL, Illegal instruction. 
#0 0x00007f58e9efd019 in ??() 

這意味着我的程序崩潰是由於在0x00007f58e9efd019地址存儲非法指令。然後我切換到ASM佈局檢查執行的最後一條指令:

(gdb) layout asm 
>|0x7f58e9efd019 vpmaskmovd (%r8),%ymm15,%ymm0 
|0x7f58e9efd01e vpmaskmovd %ymm0,%ymm15,(%rdi) 
|0x7f58e9efd023 add $0x4,%rdi 
|0x7f58e9efd027 add $0x0,%rdi 

這是指令vpmaskmovd導致錯誤。顯然,我試圖在缺乏AVX2指令集支持的系統上運行鍼對AVX2架構的程序。

$ cat /proc/cpuinfo | grep avx2 

最後,我確認了vpmaskmovd is an AVX2 only instruction

+0

我意識到我的答案並不完全符合其中一個問題要求:「確定不使用調試工具的錯誤指令」:/儘管如此,我認爲答案可能對其他用戶有用,所以我寧願放棄它。另外,正如Michael Burr評論的那樣,通過設置不同的目標體系結構「(gdb)集體系結構,可以將核心轉儲從目標機器拉到構建機器並從那裏調試核心(調試工具可用) 「。 – 2016-10-24 17:19:46

+0

我想添加,如果你的程序崩潰了,在按照上述步驟操作之前用'-ggdb'構建 – ComputerSaysNo 2017-06-01 00:52:21

+1

在試圖在僅SSE2虛擬機上使用PMADDUBSW的程序出現類似問題,謝謝:) – Joril 2018-02-15 13:19:21