这本书的第 3 章名为 Computer Systems Architecture: A programmer's perspective ,据说这样的实现
testl %eax, %eax
cmovne (%eax), %edx
无效,因为如果预测失败,那么我们将进行 NULL 解引用。它还指出我们应该使用分支代码。
不过,使用条件跳转不会导致相同的结果吗?例如:
.L1:
jmp *%eax
testl %eax, %eax
jne .L1
是否有可能欺骗 gcc 为 x86-32 输出类似的内容?假设我有一个指向函数的指针数组,其中有些是有效的,有些是无效的,并且我调用每个不为 NULL 的指针。
最佳答案
没有。如果 jmp
指令是由于测试和跳转而被证明无效的推测执行的一部分,您应该无法检测到该指令的乱序操作数获取。
cmove__
指令是 precisely documented to cause a fault if a memory access operand would cause a fault ,即使条件不满足。换句话说,这不是投机执行。它是指令语义的一部分。有条件的是移动到目的地,而不是获取。
jmp
指令没有如此记录。
我不明白你的示例代码的要点,因为内存操作*%eax
没有条件。如果%eax
包含零,那么无条件执行jmp *%eax
时的取指肯定会导致错误。这是正确的行为。如果您测试 %eax
并跳过错误引用。
testl %eax, %eax
je .L1
jmp *%eax
.L1:
不可能有问题。 *%eax
的推测执行不会导致错误,除非推测被证明是有效的,即真正的控制路径。这类似于错误操作码、除以零等的行为:正常的程序语义不受推测执行的影响。
无序读取和存储真正导致各种有趣问题的地方是在多重处理中。 This article and also its first part in the preceeding issue关于这个主题的讨论非常精彩。
关于assembly - 分支预测会使我的程序崩溃吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24611405/