У меня есть несколько вопросов об ошибках переполнения в архитектуре x86 или x86_64.В последнее время я читал о целочисленных переполнениях.Обычно, когда арифметическая операция приводит к переполнению целого числа, устанавливается бит переноса или бит переполнения в регистре FLAGS.Но, очевидно, согласно этой статье , переполнения, возникающие в результате операций деления, не устанавливают бит переполнения, а скорее вызывают аппаратное исключение, подобное тому, когда вы делите на ноль.
Теперь целочисленные переполнения, возникающие в результате деления, встречаются намного реже, чем, скажем, умножение.Есть только несколько способов вызвать переполнение деления.Одним из способов было бы сделать что-то вроде:
int16_t a = -32768;
int16_t b = -1;
int16_t c = a / b;
В этом случае, из-за представления двух дополнений целых чисел со знаком, вы не можете представить положительное значение 32768 в 16-разрядном целом числе со знаком, поэтому делениеПереполнение операции приводит к ошибочному значению -32768.
Несколько вопросов:
1) Вопреки тому, что говорится в этой статье, вышеприведенное НЕ вызывало аппаратное исключение.Я использую машину x86_64 под управлением Linux, и когда я делю на ноль, программа завершается с 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), слишком мал, чтобы соответствовать частному.Поэтому я не понимаю, почему здесь не возникает аппаратная ошибка.