C非法指令

问题描述

下面是我编写的c程序的打印件,演示了我正在运行的程序,最后是关于编译器的一些信息。

➜  illegalInstructionDebug cat illegal.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void func(int* Z){
    Z[-11] = acos(2);
}

int main(){
    fflush(stdout);
    printf("");
    fflush(stdout);
    int X[3];
    int Z[3];
    for (int n=0;0!=0;);
    func(Z);
}
➜  illegalInstructionDebug gcc illegal.c; ./a.out
[1]    28836 illegal hardware instruction  ./a.out
➜  illegalInstructionDebug clang --version
Apple clang version 11.0.3 (clang-1103.0.32.62)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLinetools/usr/bin
➜  illegalInstructionDebug

我在编写程序时遇到了非法指令错误,这是我以前从未见过的,所以我决定尝试找到一个最小的工作示例,以便找出与段错误或其他类型有何区别的原因错误。奇怪的是,程序中的微小更改似乎会使它返回段错误而不是非法的指令错误。尽管如此,我还是设法将程序简化为一个较小的工作示例。话虽如此,该程序对于一个最小的工作示例仍然相当庞大。

我的问题首先是为什么我会收到非法的指令错误,其次是什么是非法的指令错误。另外,如果此错误是我的机器特有的,那我也将感兴趣。这个程序有很多奇怪的属性。例如,似乎导致错误所需的数字为-11。

解决方法

void func(int *Z){
    Z[-11] = acos(2);
}

最有可能会覆盖堆栈中的某些 code 地址。最有可能是寄信人地址。由于堆栈是在x86-64上扩展的,并且您正在写东西到较低的地址,因此这意味着在保留Z的空间后,将返回地址放置在堆栈 中,因此我想这会到达func()的寄信人地址。而且更重要的是,您将覆盖寄信人地址的一半

acos(2)是一个域错误,返回NaN,在我的GCC上将其转换为int导致INT_MIN被写入此处...您实际上应该使用调试器并查看在发生崩溃的情况下,我想它的地址以十六进制表示形式包含很多f

如果从RIP开始的字节未解码为有效的x86-64指令或for other reasons,则会引发无效指令。