当您执行CPU不支持的指令时会发生什么?

Kel*_*len 2 linux x86-64 avx

如果CPU尝试执行已使用CPU不支持的某些指令编译的二进制文件,会发生什么.我特别想知道在旧处理器上运行的一些新的AVX指令.

我假设这可以进行测试,理论上可以向用户显示友好消息.据推测,大多数低级别的图书馆将代表您进行检查.假设你没有做这个检查,你会发生什么?您的流程会收到什么信号?

Mar*_*oom 6

可以将新指令设计为"遗留兼容",或者不能.
对于前一类属于类似指令tzcntxacquire具有在旧架构中产生有效指令的编码的指令:tzcnt被编码为 rep bsfxacquire仅仅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调度程序或明确检查指令的存在.