通过本书第3章《计算机系统体系结构:程序员的视角》,可以看出,像
这样的实现testl %eax, %eax
cmovne (%eax), %edx
是无效的,因为如果预测失败,那么我们将有NULL解引用。它还指出,我们应该使用分支代码。
但是,使用条件跳转不会导致相同的结果吗?例如:
.L1:
jmp *%eax
testl %eax, %eax
jne .L1
有可能欺骗gcc输出类似于x86-32的东西吗?假设我有一个指向函数的指针数组,其中有些是有效的,有些是无效的,我调用每个不是NULL的。
No。如果jmp
指令是由于测试和跳转而被证明无效的推测执行的一部分,那么您应该无法检测到它的乱序操作数获取。
如果内存访问操作数会导致错误,即使不满足条件,cmove__
指令也会导致错误。换句话说,这不是投机执行。它是指令语义的一部分。有条件的是移动到目的地,而不是取回
jmp
指令没有这样的文件。
我没有得到你的示例代码的点,因为在内存操作*%eax
上没有条件。如果%eax
包含零,那么在无条件执行jmp *%eax
时的取操作肯定会导致错误。这是正确的行为。如果您测试%eax
并跳过错误引用。
testl %eax, %eax
je .L1
jmp *%eax
.L1:
不可能有问题。*%eax
的投机执行不会导致故障,除非投机被证明是有效的,即真正的控制路径。这类似于错误操作码的行为,除零等:正常的程序语义不受推测执行的影响。
无序读取和存储确实在多处理中引起了各种有趣的问题。