3.4.2. Команды деления
Деление, как и умножение, реализуется двумя командами, предназначенными для знаковых и беззнаковых чисел:
DIV <операнд> ; Беззнаковое деление IDIV <операнд> ; Знаковое деление
В командах указывается только один операнд – делитель, который может быть регистром или ячейкой памяти, но не может быть непосредственным операндом. Местоположение делимого и результата для команд деления фиксировано.
Если делитель имеет размер 1 байт, то делимое берётся из регистра AX. Если делитель имеет размер 2 байта, то делимое берётся из регистровой пары DX:AX. Если же делитель имеет размер 4 байта, то делимое берётся из регистровой пары EDX:EAX.
Поскольку процессор работает с целыми числами, то в результате деления получается сразу два числа – частное и остаток. Эти два числа также помещаются в определённые регистры. Если делитель имеет размер 1 байт, то частное помещается в регистр AL, а остаток – в регистр AH. Если делитель имеет размер 2 байта, то частное помещается в регистр AX, а остаток – в регистр DX. Если же делитель имеет размер 4 байта, то частное помещается в регистр EAX, а остаток – в регистр EDX.
mov ax, 127 mov bl, 5 div bl ; AL = 19h = 25, AH = 02h = 2 mov ax, 127 mov bl, -5 idiv bl ; AL = e7h = -25, AH = 02h = 2 mov ax, -127 mov bl, 5 idiv bl ; AL = e7h = -25, AH = feh = -2 mov ax, -127 mov bl, -5 idiv bl ; AL = 19h = 25, AH = feh = -2 ; x = a * b + c mov eax, a imul b add eax, c ; Операнды команды сложения вычисляются слева направо mov x, eax ; x = a + b * c mov eax, b imul c add eax, a ; Операнды команды сложения вычисляются справа налево mov x, eax
3.5. Изменение размера числа
В операциях деления размер делимого в два раза больше, чем размер делителя. Поэтому нельзя просто загрузить данные в регистр EAX и поделить его на какое-либо значение, т.к. в операции деления будет задействован также и регистр EDX. Поэтому прежде чем выполнять деление, надо установить корректное значение в регистр EDX, иначе результат будет неправильным. Значение регистра EDX должно зависеть от значения регистра EAX. Тут возможны два варианта – для знаковых и беззнаковых чисел.
Если мы используем беззнаковые числа, то в любом случае в регистр EDX необходимо записать значение 0: aaaaaaaah → 00000000aaaaaaaah.
Если же мы используем знаковые числа, то значение регистра EDX будет зависеть от знака числа: 55555555h → 0000000055555555h, aaaaaaaah → ffffffffaaaaaaaah.
Записать значение 0 не сложно, а вот для знакового расширения необходимо анализировать знак числа. Однако нет необходимости делать это вручную, т.к. язык ассемблера имеет ряд команд, позволяющих расширять байт до слова, слово до двойного слова и двойное слово до учетверённого слова.
cbw ; Знаковое расширение AL до AX cwd ; Знаковое расширение AX до DX:AX cwde ; Знаковое расширение AX до EAX cdq ; Знаковое расширение EAX до EDX:EAX
Таким образом, если делитель имеет размер 2 или 4 байта, то нужно устанавливать значение не только регистра AX/EAX, но и регистра DX/EDX. Если же делитель имеет размер 1 байт, то можно просто записать делимое в регистр AX.
x dd ? mov eax, x ; Заносим в регистр EAX значение переменной x, которое заранее неизвестно cdq ; Знаковое расширение EAX в EDX:EAX mov ebx, 7 idiv ebx
В языке ассемблера существуют также команды, позволяющие занести в регистр значение другого регистра или ячейки памяти со знаковым или беззнаковым расширением.
MOVSX <операнд1>, <операнд2> ; Знаковое расширение – старшие биты заполняются знаковым битом MOVZX <операнд1>, <операнд2> ; Беззнаковое расширение – старшие биты заполняются нулём
Операнд1 и операнд2 могут иметь любой размер. Понятно, что операнд1 должен быть больше, чем операнд2. В случае равенства размера операндов следует использовать обычную команду пересылки MOV, которая выполняется быстрее.
Рассмотрим пример: необходимо вычислить x * x * x, где x – 1-байтовая переменная.
Do'stlaringiz bilan baham: |