Вызывает ошибку переполнения деления (x86)

У меня есть несколько вопросов об ошибках переполнения разделов на архитектуре x86 или x86_64. В последнее время я читал о целочисленных переполнениях. Обычно, когда арифметическая операция приводит к целочисленному переполнению, устанавливается бит переноса или бит переполнения в регистре FLAGS. Но, очевидно, согласно этой статье , переполнения, возникающие в результате операций деления, не устанавливают бит переполнения, а скорее вызывают аппаратное исключение, подобное тому, как при делении на ноль.

Теперь целочисленные переполнения в результате деления встречаются гораздо реже, чем, скажем, умножение. Есть только несколько способов вызвать переполнение деления. Один из способов - это сделать что-то вроде:

int16_t a = -32768;
int16_t b = -1;
int16_t c = a / b;

В этом случае, из-за представления дополнения до двух целых чисел со знаком, вы не можете представить положительное число 32768 в 16-разрядном целом числе со знаком, поэтому операция деления переполняется, что приводит к ошибочному значению -32768.

Несколько вопросов:

1) Вопреки тому, что говорится в этой статье, вышеупомянутое НЕ вызвало аппаратного исключения. Я использую машину x86_64 под управлением Linux, и когда я делю на ноль, программа завершается с исключением с плавающей запятой . Но когда я вызываю переполнение деления, программа продолжает работу в обычном режиме, молча игнорируя ошибочное частное. Так почему же это не вызывает аппаратного исключения?

2) Почему ошибки деления так серьезно обрабатываются аппаратным обеспечением, в отличие от других арифметических переполнений? Почему аппаратное обеспечение должно молчаливо игнорировать переполнение умножения (которое гораздо может произойти случайно), но предполагается, что переполнение деления вызовет фатальное прерывание?

=========== EDIT ==============

Хорошо, спасибо всем за ответы. Я получил ответы, в которых говорилось, что указанное выше 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), слишком мал, чтобы соответствовать частному. Так что я не Я понимаю, почему здесь не возникает аппаратной ошибки.

7
задан Channel72 8 October 2010 в 16:37
поделиться