如果CPU尝试执行已使用CPU不支持的某些指令编译的二进制文件,会发生什么.我特别想知道在旧处理器上运行的一些新的AVX指令.
我假设这可以进行测试,理论上可以向用户显示友好消息.据推测,大多数低级别的图书馆将代表您进行检查.假设你没有做这个检查,你会发生什么?您的流程会收到什么信号?
可以将新指令设计为"遗留兼容",或者不能.
对于前一类属于类似指令tzcnt或xacquire具有在旧架构中产生有效指令的编码的指令:tzcnt被编码为
rep bsf和xacquire仅仅repne.
语义当然是不同的.
对于第二类属于大多数新指令,AVX是一个流行的例子.
当CPU遇到无效或保留的编码时,它会生成#UD(用于UnDefined)异常 - 即中断号6.
Linux内核在早期为#UD设置了IDT条目:entry_64.S
idtentry invalid_op do_invalid_op has_error_code=0
Run Code Online (Sandbox Code Playgroud)
do_invalid_op使用宏生成的入口点traps.c:
DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op)
Run Code Online (Sandbox Code Playgroud)
宏DO_ERROR生成一个调用do_error_trap同一文件的函数(这里).
do_error_trap使用fill_trap_info(在同一文件中,这里)创建siginfo_t包含Linux信号信息的结构:
case X86_TRAP_UD:
sicode = ILL_ILLOPN;
siaddr = uprobe_get_trap_addr(regs);
break;
Run Code Online (Sandbox Code Playgroud)
从那里发生以下呼叫:
do_trap在在在traps.c
force_sig_infosignal.c
specific_send_sig_infosignal.c
这最终会导致为SIGILL违规过程调用信号处理程序.
以下程序是一个生成#UD的非常简单的示例
BITS 64
GLOBAL _start
SECTION .text
_start:
ud2
Run Code Online (Sandbox Code Playgroud)
我们可以strace用来检查运行该程序收到的信号
--- SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x400080} ---
+++ killed by SIGILL +++
Run Code Online (Sandbox Code Playgroud)
正如所料.
正如Cody Gray评论的那样,库通常不依赖于SIGILL,而是使用CPU调度程序或明确检查指令的存在.