我遇到了一个有趣的情况,代码如下:
static void DivideByZero() {
// volatile to prevent compiler optimizations.
volatile float zero = 0.0f;
volatile float result __attribute__((unused)) = 123.0f / zero;
}
DivideByZero();
int raised = fetestexcept(FE_DIVBYZERO | FE_OVERFLOW);
ASSERT_TRUE((raised & FE_DIVBYZERO) != 0);
当我使用
KVM
支持运行qemu设备时,得到了以下结果: FE_DIVBYZERO !=0; //and it's ok
但是当我运行同一个源而不支持
KVM
时: FE_DIVBYZERO ==0; //and it's not ok
据我所知,这种情况会发生,因为在
mxcsr
中没有设置寄存器位(div by zero)。但我不明白为什么这一点没有设定。有什么想法吗?
更新:
基于qemu的
android
仿真器也出现了同样的情况。emulator -avd test -qemu
返回:feu divbyzero!=0;
emulator -avd test -qemu -disable-kvm
返回:feu divbyzero==0;
最佳答案
MXCSR
寄存器在
Intel® 64 and IA-32 Architectures Software Developer’s Manual
在现代x86处理器上,编译器使用与指令相同的资源将浮点操作映射为scalar
simd。vector (SSE)
寄存器控制MXCSR
和scalar
浮点指令的操作。我在下面包含了描述MXCSR的相关部分。vector (SSE)
是除以零掩码,如果清除(0),则当检测到除以零时,CPU将引发异常。当您在虚拟机中运行时,异常被“虚拟化”,它们由“虚拟机管理程序”处理,在您的情况下是KVM。然后,管理程序决定是否将异常反映回来宾虚拟机。我的理论是清除除以零掩码,引发异常,kvm和/或qemu正在清除指示发生了除以零异常的标志MXCSR[9]
,并恢复虚拟机。因此,这可能是kvm/qemu中的一个bug。
您可以在MXCSR[2]
之前发出fegetexcept(),以确定被零除的异常是否被屏蔽(1)或不被屏蔽(0)。如果它没有被屏蔽,那么您可以使用fedisableexcept()来屏蔽它。