x86 之类的指令集是否得到更新?如果是这样,如何保证向后兼容性?
Do instruction sets like x86 get updated? If so, how is backwards compatibility guaranteed?
旧处理器如何知道如何解码它不知道的新指令?
大多数时候,旧处理器会有“未定义指令”异常。该指令未在旧 CPU.
中定义
在极少数情况下,该指令将作为不同的指令执行。当新指令通过强制性前缀编码时会发生这种情况。例如,PAUSE 被编码为 REP NOP,因此它在较早的 CPUs 上没有执行。
新指令使用以前未使用的操作码,或其他方式来查找更多“编码 space”(例如,以前对给定操作码没有任何意义的前缀)。
How would an older processor know how to decode new instructions it doesn't know about?
不会。想要在旧 CPU 和新 CPU 上工作的二进制文件必须将自己限制在基线功能集,或者在 运行 时间检测 CPU 功能并设置函数指针到 select 几个重要功能的版本。 (又名“运行时间调度”。)
x86 有一个很好的机制(cpuid
指令)让代码查询 CPU 特性而不需要任何内核支持。其他一些 ISA 需要将 CPU 信息硬编码到 OS 中或通过 I/O 访问检测到,因此唯一可行的方法是内核将信息导出到 user-space in一种 OS 特定的方式。
或者,如果您是在具有更新的 CPU 的机器上从源代码构建并且不关心旧的 CPU,您可以使用 gcc -O3 -march=native
让 GCC 使用当前 CPU 支持的所有 ISA 扩展,使二进制文件会在旧的 CPU 上出错。 (例如 x86 #UD(未定义指令)硬件异常,导致 OS 向进程传递 SIGILL 或等效信息。)
或者在某些情况下,新指令可能会解码为旧 CPU 上的其他内容,例如x86 lzcnt
解码为 bsr
,并在较旧的 CPU 上忽略了 REP 前缀,因为 x86 基本上没有未使用的操作码(在 32 位模式下)。有时这种“解码为其他东西”实际上作为优雅的回退很有用,允许透明地使用新指令,特别是 pause
= rep nop
= nop
在旧的 CPUs 上不知道。因此代码可以在自旋循环中使用它而无需检查 CPUID.
-march=native
对于服务器来说很常见,您只是在该服务器上设置 运行,而不是制作二进制文件来分发。
旧处理器如何知道如何解码它不知道的新指令?
大多数时候,旧处理器会有“未定义指令”异常。该指令未在旧 CPU.
中定义在极少数情况下,该指令将作为不同的指令执行。当新指令通过强制性前缀编码时会发生这种情况。例如,PAUSE 被编码为 REP NOP,因此它在较早的 CPUs 上没有执行。
新指令使用以前未使用的操作码,或其他方式来查找更多“编码 space”(例如,以前对给定操作码没有任何意义的前缀)。
How would an older processor know how to decode new instructions it doesn't know about?
不会。想要在旧 CPU 和新 CPU 上工作的二进制文件必须将自己限制在基线功能集,或者在 运行 时间检测 CPU 功能并设置函数指针到 select 几个重要功能的版本。 (又名“运行时间调度”。)
x86 有一个很好的机制(cpuid
指令)让代码查询 CPU 特性而不需要任何内核支持。其他一些 ISA 需要将 CPU 信息硬编码到 OS 中或通过 I/O 访问检测到,因此唯一可行的方法是内核将信息导出到 user-space in一种 OS 特定的方式。
或者,如果您是在具有更新的 CPU 的机器上从源代码构建并且不关心旧的 CPU,您可以使用 gcc -O3 -march=native
让 GCC 使用当前 CPU 支持的所有 ISA 扩展,使二进制文件会在旧的 CPU 上出错。 (例如 x86 #UD(未定义指令)硬件异常,导致 OS 向进程传递 SIGILL 或等效信息。)
或者在某些情况下,新指令可能会解码为旧 CPU 上的其他内容,例如x86 lzcnt
解码为 bsr
,并在较旧的 CPU 上忽略了 REP 前缀,因为 x86 基本上没有未使用的操作码(在 32 位模式下)。有时这种“解码为其他东西”实际上作为优雅的回退很有用,允许透明地使用新指令,特别是 pause
= rep nop
= nop
在旧的 CPUs 上不知道。因此代码可以在自旋循环中使用它而无需检查 CPUID.
-march=native
对于服务器来说很常见,您只是在该服务器上设置 运行,而不是制作二进制文件来分发。