2012-04-27 41 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