通过本书第3章“{3}}”,它表示像
这样的实现testl %eax, %eax
cmovne (%eax), %edx
无效,因为如果预测失败,那么我们将有NULL解除引用。还说我们应该使用分支代码。
但是,不使用条件跳转会导致相同的结果吗?例如:
.L1:
jmp *%eax
testl %eax, %eax
jne .L1
是否有可能欺骗gcc为x86-32输出类似的内容?假设我有一个指向函数的指针数组,其中一些是有效的,有些则不是,我称每个函数都不是NULL。
答案 0 :(得分:5)
没有。如果jmp
指令是由于测试和跳转而证明无效的推测执行的一部分,则您应该无法检测到cmove__
指令的无序操作数提取。
即使条件不满足,jmp
指令也是precisely documented to cause a fault if a memory access operand would cause a fault。换句话说,这不是推测性执行。它是指令语义的一部分。 移动是有条件的,而不是获取。
*%eax
指令没有记录在案。
我没有明白你的示例代码,因为内存操作%eax
没有条件。如果jmp *%eax
包含零,则无条件执行%eax
中的提取肯定会导致错误。这是正确的行为。如果您测试testl %eax, %eax
je .L1
jmp *%eax
.L1:
并跳转错误引用。
*%eax
不会有问题。 {{1}}的推测执行不会导致错误,除非推测证明是有效的,即真正的控制路径。这类似于坏操作码的行为,除以零等:正常的程序语义不受推测执行的影响。
无序的提取和存储确实做导致各种有趣的问题在于多处理。 This article and also its first part in the preceeding issue是对此主题的精彩讨论。