在编译下面的代码后,该功能似乎没有按预期工作。
int cread(int *xp){
return (xp?*xp:0);
}
我在汇编版本中提取对应物,如下所示。
注册xp
中的 %edx
movl $0, %eax
testl %edx, %edx
cmovne (%edx), %eax
有人能告诉我为什么即使测试失败,指针xp
仍被cmovne
取消引用? ZF
1
testl
时,%edx
的{{1}}设置不是0
?
答案 0 :(得分:3)
英特尔指令集手册似乎表明如果不满足条件,则不会读取CMOV操作数。 (我怀疑手册中给出的指令的“算法”并不完全正确。)
显然,其他人不同意;看到明确的警告here:
如果源操作数是内存操作数,则无论是否满足条件,都始终读取它。这意味着无论从内存读取生成什么异常,都会生成。如果读取的内存会导致#GP或#PG,那么就这样吧。
我怀疑其原因是:指令解码器在指令完全解码并准备好执行之前,尽可能早地读取指令,计算有效地址并发出存储器读取。因此,对内存的读取会提前调度/执行并导致陷阱。直到执行单元实际到达CMOV它才知道不需要存储器读取,并且延迟启动它会使指令真正变慢,并使指令预取逻辑复杂化。
我只使用它的寄存器寄存器形式,它不会陷阱。