【发布时间】:2020-12-20 04:30:15
【问题描述】:
下面是我写的一个 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 才能导致错误。
【问题讨论】:
-
您很可能会覆盖返回地址,这会导致处理器获取指令的中间字节。
-
更一般地说,您试图解释“未定义的行为”。当您的程序有 UB 时,它可能会出现段错误、出现非法指令错误、似乎可以工作或任何其他行为。尝试解释为什么
-10导致行为X 和-11导致行为Y 是没有成效的。这不是批评任何理解“非法指令”意味着什么的愿望,而是要意识到试图解释UB 的一般概念对于特定的一组条件是无效的。 -
如果您编译程序,编译器会将 C 代码转换为硬件指令。每种计算机和操作系统的处理方式都不同,因此编译器只能保证在没有未定义行为的情况下会发生什么。如果一个函数写入不在变量内部的内存,那么它可能会覆盖对程序或操作系统很重要的东西。例如,如果一个函数覆盖了返回地址,那么当函数返回时,它可以跳转到任何地方。但是会发生什么取决于编译器和操作系统存储内容的位置以及硬件的工作方式。
-
所以,我们需要知道你的编译器和编译器命令行的确切版本,你所拥有的操作系统的确切版本,你的 CPU 的确切型号以及你的程序的确切加载位置在内存中以及(如果您的硬件没有保护内存的 MMU)在程序周围的页面中加载到内存中的内容。除非您拥有完整的内存快照以及所有其他信息,否则基本上无法预测会发生什么。基本上任何汇编语言程序员每天都会遇到的问题!
-
“非法指令”错误的一个原因是编译器在编译时检测到未定义行为时会发出
ud2或类似内容
标签: c x86-64 undefined-behavior illegal-instruction