我有几个关于 x86 或 x86_64 架构上的除法溢出错误的问题。最近我一直在阅读有关整数溢出的文章。通常,当算术运算导致整数溢出时,FLAGS 寄存器中的进位位或溢出位被置位。但显然,根据这篇文章,除法运算导致的溢出不会设置溢出位,而是触发硬件异常,类似于除以零时。
现在,除法导致的整数溢出比乘法少得多。只有几种方法可以触发除法溢出。一种方法是执行以下操作:
int16_t a = -32768;
int16_t b = -1;
int16_t c = a / b;
在这种情况下,由于有符号整数的二进制补码表示,不能在有符号的 16 位整数中表示正 32768,所以除法运算溢出,导致 -32768 的错误值。
几个问题:
1)与本文所说的相反,上述并没有导致硬件异常。我正在使用运行 Linux 的 x86_64 机器,当我除以零时,程序以Floating point exception
. 但是当我导致除法溢出时,程序照常继续,默默地忽略错误的商。那么为什么这不会导致硬件异常呢?
2) 为什么硬件对除法错误的处理如此严重,而不是其他算术溢出?为什么硬件会默默地忽略乘法溢出(更容易发生意外),而除法溢出应该触发致命中断?
===========编辑===============
好的,谢谢大家的回复。我收到的回复基本上说上述 16 位整数除法不应该导致硬件故障,因为商仍然小于寄存器大小。我不明白这一点。在这种情况下,存储商的寄存器是 16 位的 - 这太小而无法存储有符号正数 32768。那么为什么不引发硬件异常呢?
好的,让我们直接在 GCC 内联汇编中执行此操作,看看会发生什么:
int16_t a = -32768;
int16_t b = -1;
__asm__
(
"xorw %%dx, %%dx;" // Clear the DX register (upper-bits of dividend)
"movw %1, %%ax;" // Load lower bits of dividend into AX
"movw %2, %%bx;" // Load the divisor into BX
"idivw %%bx;" // Divide a / b (quotient is stored in AX)
"movw %%ax, %0;" // Copy the quotient into 'b'
: "=rm"(b) // Output list
:"ir"(a), "rm"(b) // Input list
:"%ax", "%dx", "%bx" // Clobbered registers
);
printf("%d\n", b);
这只是输出一个错误的值:-32768
. 仍然没有硬件异常,即使存储商 (AX) 的寄存器太小而无法容纳商。所以我不明白为什么这里没有引发硬件故障。