X64指令在不同的CPU上表现不同

awp*_*eet 3 x86 assembly x86-64

在一次采访中,有人问我是否知道x64指令的行为有所不同,具体取决于使用的CPU,我在任何地方找不到任何文档,有谁知道这些指令是什么以及为什么会这样?

Pet*_*des 5

有些会留下一个寄存器或一些带有未定义值的标志.英特尔和AMD可能会有所不同.

在某些情况下,这些未定义情况的实际硬件的实际行为保留了一些依赖它的旧软件的向后兼容性.例如,BSF根据英特尔的手册,使用input = 0设置ZF并使目标寄存器保留未定义的内容.但AMD的手册(以及真正的英特尔+ AMD硬件)在这种情况下不会修改目的地.(这就是为什么bsf/ bsr具有输出依赖性.)

如果计算性能差异,则有很多(请参阅标记wiki 中的链接)!


您不只是在谈论不受支持的说明,是吗?就像LAHF/SAHF在一些非常早期的x86-64 CPU中不支持长模式一样?或早期K8也不支持CMPXCHG16B.

不受支持的指令最有趣的情况是LZCNT在不支持它的CPU上解码为REP BSR.即使对于非零输入,它们也会返回相反的结果.(_tzcnt_u32(x) == 31-bsr(x)).TZCNT类似地在不支持它的CPU上解码为REP BSF,但它们做同样的事情,除非输入= 0.我之前没有提到过,因为运行相同的机器代码与运行不同相同的指令不同,但听起来这是你要求的那种东西.

我们只谈论无特权指令吗?特权指令的行为可能存在许多差异.例如,英特尔和AMD在SYSRET中都有不同的错误,Linux必须解决这些错误,以避免恶意用户空间导致内核挂起.


我不确定的另一个案例是:PREFETCHW在英特尔CPU上运行,从至少Core2到Haswell作为NOP,但在AMD CPU(以及英特尔自Broadwell)作为实际预取.

因此,有些CPU将其作为NOP运行,有些CPU将其作为预取运行(因此无论如何都没有架构上可见的效果),除非在古老的CPU中它作为非法insn出错.64位Windows8.1 显然要求PREFETCHW可以在没有故障的情况下运行(这会阻止它运行(某些?)64位Pentium4 CPU).

  • 除了显而易见的`cpuid`之外,你可以将`tzcnt`作为`rep bsf`和`lzcnt`作为`rep bsr`在CPU <Haswell上执行,因为`f3 0f bc/r`中的`f3`被解释为`rep`在那些CPU上,因此在架构上表现不同.这些是我在x64上知道_architecturally-different_行为的三个实例; 对于'xacquire/xrelease` HLE前缀的'f2/f3`的选择也可以说是重要的. (2认同)