分支预测会导致程序崩溃吗?

14

在阅读名为计算机系统结构:程序员的视角的书籍第三章时,提到了这样一种实现:

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

如果预测失败,那么“is invalid”就是无效的,因为我们将会遇到NULL引用错误。文中也指出我们应该使用分支代码。

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

.L1:
jmp *%eax

testl %eax, %eax
jne .L1

有没有可能欺骗gcc输出类似于x86-32的内容?假设我有一个指向函数的指针数组,其中一些是有效的,一些是无效的,我调用每个不为NULL的函数。


1
我不会关闭它。对我来说,这听起来是一个有效的问题。不确定它为什么被认为是太广泛了。 - TomTom
1
我认为 CPU 架构需要处理这种情况,否则就不会剩下任何可工作的程序了。这仍然是一个有趣的问题。 - Mark Ransom
4
手册说明:只有在指令的实际“按顺序”执行之后,才会发出异常和中断信号。另请参见此问题 - Jester
2
@AlexC:我认为链接的问题回答了你的确切关注点——你不会从推测执行中获得#PF异常,因为你不会从虚拟地址零获得4个字节,因为eax不是零。不,分支预测(推测执行)不会使你的程序崩溃。 - Michael Foukarakis
1
我记得有一个案例(Linux内核遇到的),其中gcc会优化掉空指针检查,如果指针先前已被解引用。我认为这是gcc利用C未定义行为进行空指针解引用,导致比鼻妖更糟糕但仍然不愉快的结果。 - user2467198
显示剩余5条评论
1个回答

5
不应该能够检测到jmp指令的乱序操作获取,如果它是一次证明由于测试和跳转无效的推测执行的一部分。 cmove__指令被精确地记录为在内存访问操作数引起故障的情况下导致故障,即使条件未满足。 换句话说,这不是推测执行的一部分。 它是指令语义的一部分。 是目标的移动是有条件的,而不是获取。 jmp指令没有这样的记录。 我不明白你的示例代码的重点,因为对内存操作*%eax没有条件。 如果%eax包含零,则无条件执行jmp *%eax中的获取将导致故障。 这是正确的行为。 如果您测试%eax并绕过错误引用。
testl %eax, %eax
je .L1
jmp *%eax
.L1:

没有问题。除非猜测执行是有效的,即真正的控制路径,否则*%eax的猜测执行不会导致故障。这类似于错误操作码、除以零等情况的行为:正常程序语义不受猜测执行的影响。

在多处理中,乱序获取和存储确实会引起各种有趣的问题。本文及其前一期的第一部分是这个主题的很好讨论。


1
一个架构不保证顺序一致性时,不需要乱序执行就能出现内存一致性问题。缓存之间通信的延迟足以导致读写操作的顺序不一致。实际上,乱序执行被提出来是为了在顺序一致性下提供良好的性能(“Is SC + ILP = RC?”,Chris Gniady等人,1999年,PDF)。 - user2467198
@PaulA.Clayton 当然你是对的。我是从另一个角度来考虑的——它增加了一些复杂性,比如在实现无等待算法的正确性时。 - Gene
@Gene:我认为你说得对,我添加了无条件的跳转,因为有条件的跳转只能与标签一起使用。我在考虑一个情况,即%eax正在计算中,它可以是0或地址。也许我们可以改进问题,使其更清晰明了? - Alex C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接