Ответ 1
Что делать
Для 32-разрядного /32-разрядного => 32-разрядного деления: zero- или знаковое расширение 32-разрядного дивиденда от EAX до 64-разрядного EDX: EAX.
Для 16-битных AX в DX: AX с cwd
или xor- cwd
.
- без знака:
XOR EDX,EDX
затемDIV divisor
- подписано:
CDQ
затемIDIV divisor
Смотрите также Когда и почему мы подписываем расширение и используем cdq с mul/div?
Почему (TL; DR)
Для 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
, что 1 0000 000A
к 1 0000 000A
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 ; before start of loop, set EDX to 0
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, в ассемблере, который я использую (встроенный ассемблер Delphi), метки, начинающиеся с @
являются локальными для функции, то есть они не мешают меткам с одинаковыми именами в других функциях.