无需调试即可查找哪个汇编指令导致非法指令错误

时间:2012-04-27 16:11:12

标签: c linux assembly x86-64 yasm

在运行我用汇编语言编写的程序时,出现Illegal instruction错误。有没有办法知道哪个指令导致错误,没有调试,因为我正在运行的机器没有调试器或任何开发系统。换句话说,我在一台机器上编译并在另一台机器上运行。我无法在我正在编译的机器上测试我的程序,因为它们不支持SSE4.2。我正在运行该程序的机器确实支持SSE4.2指令。

我认为这可能是因为我需要告诉汇编程序(YASM)识别SSE4.2指令,就像我们使用gcc一样传递-msse4.2标志。或者你认为这不是原因吗?知道如何告诉YASM识别SSE4.2指令吗?

也许我应该捕获SIGILL信号然后解码SA_SIGINFO以查看该程序的非法操作。

6 个答案:

答案 0 :(得分:30)

实际上你经常遇到非法指令错误,不是因为你的程序包含非法的操作码,而是因为你的程序中有一个错误(例如,缓冲区溢出)会使你的程序在普通数据或代码的随机地址中跳转但不是在操作码的开头。

答案 1 :(得分:23)

最近,由于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 layout 来检查最后执行的指令:

(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

答案 2 :(得分:11)

如果你可以在该系统上启用核心转储,只需运行该程序,让它崩溃,然后将核心转储从目标机器上拉到你的开发机器上,并将其加载到一个GDB中,用于调试目标架构 - 这应该是告诉你崩溃的确切位置。只需使用GDB的core命令将核心文件加载到调试器中即可。

  • 在目标上启用核心转储:

    ulimit -c unlimited
    
  • 控制核心文件命名方式的伪文件(请将这些文件命名为当前配置,写入以更改配置):

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

在我的系统上,一旦启用了核心转储,崩溃的程序将在工作目录中编写一个名为“core”的文件。这可能足以满足您的需求,但更改核心转储文件的命名方式可让您保留核心转储的历史记录(如果有必要(可能是更间歇性的问题))。

答案 3 :(得分:4)

嗯......您当然可以插入跟踪打印输出,这样您就可以快速排除代码的大部分区域。完成后,运行例如。

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

然后跳到例如你知道的函数是导致错误,并读取代码,寻找看起来很奇怪的东西。

我不完全确定objdump如何显示非法指令,但它们应该脱颖而出。

答案 4 :(得分:4)

对于手写程序集,我会怀疑堆栈管理问题导致无法返回。编写一个调试打印输出例程,保存每个寄存器并在每个函数的顶部插入一个调用。

然后你会看到你有多远......

(顺便说一句,编写机器代码时,一个好的编辑器和对汇编程序宏语法的理解是救生员。)

答案 5 :(得分:2)

在函数末尾缺少return语句可能会导致这种情况。