14

通过这本书的第 3 章,称为计算机系统架构:程序员的观点,据说这样的实现

testl %eax, %eax
cmovne (%eax), %edx

是无效的,因为如果预测失败,那么我们将取消引用 NULL。还指出我们应该使用分支代码。

不过,使用条件跳转不会导致相同的结果吗?例如:

.L1:
jmp *%eax

testl %eax, %eax
jne .L1

是否可以欺骗 gcc 为 x86-32 输出类似的东西?假设我有一个指向函数的指针数组,其中一些是有效的,一些是无效的,并且我调用每个不是 NULL 的函数。

4

1 回答 1

5

jmp否。如果指令的无序操作数提取是由于测试和跳转而被证明无效的推测执行的一部分,则 您应该无法检测到该指令的乱序操作数提取。

如果内存访问操作数会导致错误,即使条件不满足,该cmove__指令也会被精确记录为导致错误。换句话说,这不是推测执行。它是指令语义的一部分。转移到目的地是有条件的,而不是获取。

jmp指令没有如此记录。

我没有理解您的示例代码的重点,因为内存操作没有条件*%eax。如果%eax包含零,当然无条件执行中的取指jmp *%eax会导致错误。这是正确的行为。如果您测试%eax并跳过错误的参考。

testl %eax, %eax
je .L1
jmp *%eax
.L1:

不可能有问题。*%eax除非推测证明是有效的,即真正的控制路径,否则推测执行不会导致错误。这类似于错误操作码、被零除等的行为:正常程序语义不受推测执行的影响。

乱序获取和存储确实会导致各种有趣问题的地方在于多处理。 这篇文章及其上一期的第一部分是对该主题的精彩讨论。

于 2014-07-07T20:25:38.027 回答