Почему EDX должен быть 0 перед использованием инструкции DIV?

Я заметил, что в EDX содержится случайное значение по умолчанию, например 00401000, и затем я использую инструкцию DIV, например:

mov eax,10
mov ebx,5
div ebx

это вызывает ОШИБКУ ПЕРЕВОДА INTEGER. Однако, если я установлю edx до 0 и сделать то же самое, что работает. Я считал, что с помощью div приведет к частичной перезаписи eax а остаток перезаписывается edx,

Получение этой ОШИБКИ INTEGER OVERFLOW действительно смущает меня.

2 ответа

Решение

За DIV, регистры EDX а также EAX образуют одно 64-битное значение (часто отображается как EDX:EAX), который затем делится, в данном случае, на EBX,

Так что если EAX знак равно 10 или шестнадцатеричный A а также EDX скажем 20 или шестнадцатеричный 14 затем они вместе образуют шестнадцатеричное 64-битное значение 14 0000 000A или десятичный 85899345930, Если это делится на 5 результат 17179869186 или шестнадцатеричный 4 0000 0002, что является значением, которое не помещается в 32 бит.

Вот почему вы получаете целочисленное переполнение.

Если, однако, EDX были только 1, вы бы разделить гекс 1 0000 000A от 5, что приводит к гексам 3333 3335, Это не то значение, которое вы хотели, но оно не вызывает целочисленное переполнение.

Чтобы действительно разделить 32-битный регистр EAX другим 32-битным регистром, убедитесь, что вершина 64-битного значения, образованная EDX:EAX является 0,

Таким образом, перед одним делением, вы должны установить EDX в 0,

(Или для подписанного деления, cdq подписать продлить EAX в EDX:EAX до idiv)


Но EDX не всегда должен быть 0, Это может быть не настолько большим, что результат вызывает переполнение.

Один пример из моего BigInteger код:

После разделения с DIV частное находится в EAX и остаток находится в EDX, Разделить что-то вроде BigInteger, который состоит из множества DWORDS, от 10 (например, чтобы преобразовать значение в десятичную строку), вы делаете что-то вроде следующего:

    ; ECX contains number of "limbs" (DWORDs) to divide by 10
    XOR     EDX,EDX
    MOV     EBX,10
    LEA     ESI,[EDI + 4*ECX - 4] ; now points to top element of array
@DivLoop:
    MOV     EAX,[ESI]
    DIV     EBX          ; divide EDX:EAX by EBX. After that,
                         ; quotient in EAX, remainder in EDX
    MOV     [ESI],EAX
    SUB     ESI,4        ; remainder in EDX is re-used as top DWORD... 
    DEC     ECX          ; ... for the next iteration, and is NOT set to 0.
    JNE     @DivLoop

После этого цикла значение, представленное всем массивом (т.е. BigInteger) делится на 10, а также EDX содержит остаток от этого подразделения.

FWIW, в моем ассемблере, этикетки начинаются с @ являются локальными для функции, то есть они не мешают меткам с одинаковыми именами в других функциях.

Инструкция DIV делит EDX:EAX на r/m32, который следует за инструкцией DIV. Таким образом, если вам не удается установить EDX на ноль, значение, которое вы используете, становится чрезвычайно большим.

Доверие, которое помогает

Другие вопросы по тегам