Почему 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 на ноль, значение, которое вы используете, становится чрезвычайно большим.
Доверие, которое помогает