我多年来一直在编写 x86 Assembly,但从未遇到过这个。我希望有人能给我指出正确的方向,这样我就可以“Doh!”时刻。
在伪代码中,当我写
42 DIV 4
时,除法按预期工作。当我写RDRAND DIV 4
时,CPU抛出异常。我正在做无符号的 16 位算术,但我也以 32 和 64 位重现了它。
我已经在 Intel Xeon 和 Core CPU 以及 AMD EPYC 上重现了这一点...所以我认为这是故意的,而不是孤立的事情。
这是源代码。我是这样编译的:
clang -masm=intel -o div_bug div_bug.c
#include <stdio.h>
#include <stdint.h>
int main() {
printf( "div_bug\n" );
uint8_t rval;
// rdrand sets CF on success... I've tried this with and without this
// check and the program still throws an exception
// This works as expected
asm volatile (
// "try_again_1:"
"rdrand ax;" // If CF==0, then the rdrand failed... try again
// "jnc try_again_1;"
"mov ax, 42;" // This works... as expected
"mov cl, 4;"
"div cl;"
"mov %0, ah;"
:"=r" ( rval ) // Output
: // Input
:"ax", "cl", "cc" ); // Clobbers
printf( "The first return value is %u\n", rval );
// This throws a `Floating point exception (core dumped)`
asm volatile (
// "try_again_2:"
"rdrand ax;" // If CF==0, then the rdrand failed... try again
// "jnc try_again_2;"
// "mov ax, 42;" // <---- Remove this and it breaks
"mov cl, 4;"
"div cl;"
"mov %0, ah;"
:"=r" ( rval ) // Output
: // Input
:"ax", "cl", "cc" ); // Clobbers
printf( "The second return value is %u\n", rval );
}
我还在这里获得了代码仓库:https://github.com/marknelsonengineer/div_bug.git
我研究了Intel SDM中的
DIV
和RDRAND
指令,但没有看到任何明显的东西。
我期望
RDRAND
返回一个数字...我可以除以 4。
我的问题是:当分子来自
DIV
时,为什么 RDRAND
会抛出异常?
谢谢你, 马克
大多数时候你的随机数> = 1024,这意味着除以4的结果无法容纳在8位中,并且你会得到一个#DE执行。来自描述 DIV 的 Intel 手册:
IF OperandSize = 8 (* Word/Byte Operation *)
THEN
temp ← AX / SRC;
IF temp > FFH
THEN #DE; (* Divide error *)
ELSE
AL ← temp;
AH ← AX MOD SRC;
FI;
FI;