А инструкция i386 "div ah" бессмысленна? - PullRequest
8 голосов
/ 06 августа 2020

From https://www.felixcloutier.com/x86/div:

    ...
    temp ← AX / SRC;
    IF temp > FFH
        THEN #DE; (* Divide error *)
        ELSE
            AL ← temp;
            AH ← AX MOD SRC;
    FI;
    ...

Для div ah SRC будет ah. IMHO temp всегда будет больше, чем FFH, и поэтому исключение будет вызвано, так как:

  1. AX = 256 * AH + AL
  2. temp = AX / AH = ( 256 * AH + AL) / AH = 256 + AL / AH
  3. температура закончилась FFH

Я что-то здесь пропустил?

1 Ответ

9 голосов
/ 06 августа 2020

Верно, точно так же, как div edx, его нельзя использовать без ошибок. Критерий того, что 2N / N => N-бит div не переполняется, его частное - high_half(dividend) < divisor, как вы показали, поэтому использование divisor = high(dividend) всегда будет переполняться (или делиться на ноль).

Интересный момент что это гарантированный способ с одной инструкцией поднять #DE, не требуя при этом никаких инструкций для помещения значений в регистр.

(В защищенном режиме int 0 - это не точно то же самое вещь. например, под Linux, в пользовательском пространстве int 0 будет #GP -> SIGSEGV из-за разрешений на запись IDT, в то время как фактическое исключение разделения будет #DE -> SIGFPE).

Как указывает Шут, эта кодировка учитывает только 1 из 2 ^ 5 возможных кодировок F6 /6 div r/m8, считая только байт ModRM (а не огромные возможности дополнительных байтов, которые могут использовать режимы адресации).

Чтобы сделать его некодируемым, потребуются дополнительные транзисторы в декодерах. И что тогда делать с этой 2-байтовой последовательностью? #UD исключение недопустимой инструкции? Это глупо, просто пусть он поднимет #DE после обычного декодирования и попадет в исполнительный блок, как любая другая инструкция div. Или использовать его для какой-то другой специальной вещи, такой как mfence?

Вероятно, было бы неразумным дизайнерским решением, чтобы 2-байтовый машинный код для div ah на самом деле означал какую-то совершенно другую отдельную инструкцию. . В любом случае, этот корабль плыл с 8086, где он поднимет #DE, а не #UD; любое изменение нарушило бы эту обратную совместимость. Поскольку существуют менее навязчивые способы найти новое пространство для кодирования новых кодов операций (например, незаконные кодировки lds и les или что-то еще, что префиксы VEX заимствуют ), Intel и AMD еще не опустился до такого безумия. Эти кодировки 32-битного режима LES / LDS уже подняли #ud вместо другого исключения и, что более важно, имели больше запасных бит, поэтому префиксы VEX имели место для фактического кодирования некоторых полей в этих 2- или 3-байтовых префиксах.

...