ARM Illegal Instruction错误初窥
2016-01-19 14:41
309 查看
最近调程序,出现illegal instruction问题,没有头绪。 索性把illegal instruction好好窥探一下。
1.现象
当执行一段程序时,发生错误,并报”illegal instruction”错
复制代码
typedef void(*FUNC)(void);
int main(void)
{
const static unsigned char insn[4] = { 0xff, 0xff, 0xff, 0xff };
FUNC function = (FUNC) insn;
function();
}
复制代码
编译执行之:
$ gcc -o sigill illegal_instruction.c
$ ./sigill
Illegal instruction
2.关于"illegal instruction"
illegal instruction,即SIGILL, 是POSIX标准中提供的一类错误。 从名字上看,SIGILL是启动的某个进程中的某一句不能被CPU识别成正确的指令。 此类错误是由操作系统发送给进程的,在进程试图执行一些形式错误、未知或者特权指令时操作系统会使用SIGILL信号终止程序。 SIGILL对应的常数是4.
3.造成SIGILL的原因
3.1 将不正确的数据段写入代码段
进程在代码段中的数据是要被作为一个指令执行的。 若不小心覆盖了已有的代码段,可能会得到错误格式的指令。 这种错误尤其在Just-In-Time即时编译器中最可能出现。
同样,如果不小心覆盖了栈上活跃记录中的返回地址,程序就可能根据这个错误地址,执行没有意义的内存中的数据,进而操作。
进一步可以认为,任何导致数据错误的问题都可能带来illegal instruction问题。比如硬盘发生故障。
3.2 指令集的演进
比如SIMD指令,自从奔腾4开始有MMX,X86的芯片就开始不停的增加和拓宽SIMD支持,SSE、SSE2、SSE3、SSE42、AVX、AVX2。 默认情况下,很多编译器都在O2或者O3中开了自动向量化,这就导致很多在新体系结构中编译的可执行程序,在老机器上运行时会有illegal instruction问题。
3.3 工具链BUG
对于普通C语言通过编译器生成的可执行程序。一般都已经通过严格的测试,不会随便发生这种问题。 所以如果你遇到这种错,并且试过了静态链,而且程序中没有嵌入式汇编,基本可以断定是工具链出了问题。 编译器?汇编器或者链接器。
3.4 访存对齐或浮点数格式问题
根据Heiher的经验,请注意出现错误的指令可能和访存地址指令有关。 另外,浮点数的格式是否符合IEEE的标准也可能会有影响。
4. 错误排查指南
程序中有没有特权指令、或者访问特权寄存器
有没有将在较新CPU上编译得到的可执行文件拿到老CPU上运行
程序中有没有嵌入式汇编,先检查。
一般编译器很少会生成有这种问题的代码
X86平台上要尤其注意64位汇编指令和32位汇编指令的混用问题
程序有在进程代码段空间写数据的机会吗?
栈操作够安全吗?
注意程序的ABI是否正确
尤其是动态链和静态链是否处理的正确,尽量避免动态链的可执行文件调用错误库的问题(ARM的EABI,MIPS的N32/O32/N64都很可能出这种问题)
用的工具链靠谱吗?
以上是我转载的一篇博主的博客,感谢博主的分享,然后备上自己的一点小总结:
这是我第二次遇到越界问题,程序越界是一个比较麻烦的事,因为它的现象不确定,经常是程序越界时不出错,之后程序运行时才出错。
这次的错误是因为数组越界了,程序执行时没有提示错误,当程序在嵌套调用的底层一直返回时,在返回过程中出错,这种情况就肯定是底层函数越界踩了上层函数的数据
越界一般形式:数组越界:int arr[3]; arr[-1]或者arr[4]
指针越界:野指针使用,指针超出申请内存范围
字符串处理函数越界:buf[20]; memcpy(buf, str, strlen(str));
1.现象
当执行一段程序时,发生错误,并报”illegal instruction”错
复制代码
typedef void(*FUNC)(void);
int main(void)
{
const static unsigned char insn[4] = { 0xff, 0xff, 0xff, 0xff };
FUNC function = (FUNC) insn;
function();
}
复制代码
编译执行之:
$ gcc -o sigill illegal_instruction.c
$ ./sigill
Illegal instruction
2.关于"illegal instruction"
illegal instruction,即SIGILL, 是POSIX标准中提供的一类错误。 从名字上看,SIGILL是启动的某个进程中的某一句不能被CPU识别成正确的指令。 此类错误是由操作系统发送给进程的,在进程试图执行一些形式错误、未知或者特权指令时操作系统会使用SIGILL信号终止程序。 SIGILL对应的常数是4.
3.造成SIGILL的原因
3.1 将不正确的数据段写入代码段
进程在代码段中的数据是要被作为一个指令执行的。 若不小心覆盖了已有的代码段,可能会得到错误格式的指令。 这种错误尤其在Just-In-Time即时编译器中最可能出现。
同样,如果不小心覆盖了栈上活跃记录中的返回地址,程序就可能根据这个错误地址,执行没有意义的内存中的数据,进而操作。
进一步可以认为,任何导致数据错误的问题都可能带来illegal instruction问题。比如硬盘发生故障。
3.2 指令集的演进
比如SIMD指令,自从奔腾4开始有MMX,X86的芯片就开始不停的增加和拓宽SIMD支持,SSE、SSE2、SSE3、SSE42、AVX、AVX2。 默认情况下,很多编译器都在O2或者O3中开了自动向量化,这就导致很多在新体系结构中编译的可执行程序,在老机器上运行时会有illegal instruction问题。
3.3 工具链BUG
对于普通C语言通过编译器生成的可执行程序。一般都已经通过严格的测试,不会随便发生这种问题。 所以如果你遇到这种错,并且试过了静态链,而且程序中没有嵌入式汇编,基本可以断定是工具链出了问题。 编译器?汇编器或者链接器。
3.4 访存对齐或浮点数格式问题
根据Heiher的经验,请注意出现错误的指令可能和访存地址指令有关。 另外,浮点数的格式是否符合IEEE的标准也可能会有影响。
4. 错误排查指南
程序中有没有特权指令、或者访问特权寄存器
有没有将在较新CPU上编译得到的可执行文件拿到老CPU上运行
程序中有没有嵌入式汇编,先检查。
一般编译器很少会生成有这种问题的代码
X86平台上要尤其注意64位汇编指令和32位汇编指令的混用问题
程序有在进程代码段空间写数据的机会吗?
栈操作够安全吗?
注意程序的ABI是否正确
尤其是动态链和静态链是否处理的正确,尽量避免动态链的可执行文件调用错误库的问题(ARM的EABI,MIPS的N32/O32/N64都很可能出这种问题)
用的工具链靠谱吗?
以上是我转载的一篇博主的博客,感谢博主的分享,然后备上自己的一点小总结:
这是我第二次遇到越界问题,程序越界是一个比较麻烦的事,因为它的现象不确定,经常是程序越界时不出错,之后程序运行时才出错。
这次的错误是因为数组越界了,程序执行时没有提示错误,当程序在嵌套调用的底层一直返回时,在返回过程中出错,这种情况就肯定是底层函数越界踩了上层函数的数据
越界一般形式:数组越界:int arr[3]; arr[-1]或者arr[4]
指针越界:野指针使用,指针超出申请内存范围
字符串处理函数越界:buf[20]; memcpy(buf, str, strlen(str));
相关文章推荐
- iOS Grand Central Dispatch (GCD) 的一般使用详解
- C语言函数指针的使用举例
- 【Modern OpenGL】光照映射 LightingMaps
- 《Redis系列专题》 之 大规模互联网应用Redis架构要点(精华)
- 本地推送
- 选择排序-selectSort
- 创建maven web工程
- 用RxJava实现事件总线(Event Bus)
- [solr] - IKAnalyzer 扩展分词库
- MVC中设置为只读
- 多线程初探(六)
- Java ObjectMapper String转HashMap
- EF报LINQ to Entities 不识别方法“Web_JZRepository.Models.copy_materials_details get_Item(Int32) ”,因此该方法无法转换为存储表达式。
- 【小松教你手游开发】【unity实用技能】Unity3D中Assetbundle技术使用心得
- oracle rac linux下安装
- 关于JAVA的修饰符
- [solr] - defType - 查询权重排序
- 表单中的一些隐晦的bug
- 单点登录实现原理
- JEMETER