Умножение. Инструкции mul и imul

Последнее обновление: 12.10.2023

Инструкции mul и imul умножает два целых числа. imul умножает числа со знаком, а mul - беззнаковые числа. Обе инструкции принимают один операнд - регистр или адрес в памяти, который умножается на значение в регистре RAX. Результат помещается в регистры RAX/RDX:

mul operand8   ; если операнд 8-разрядный, результат в AX
mul operand16  ; если операнд 16-разрядный, результат в DX:AX
mul operand32  ; если операнд 32-разрядный, результат в EDX:EAX
mul operand64  ; если операнд 64-разрядный, результат в RDX:RAX

В качестве операнда можно передавать регистр или переменную/адрес в памяти. Единственный операнд умножается на соответствующий его размеру регистр AL/AX/EAX/RAX. Результат умножения двух n-битных значений может потребовать 2×n бит. Следовательно, если операнд - 8-битное число, то для результата может потребоваться 16 бит. Аналогично, 16-битный операнд дает 32-битный результат и т.д.

mul operand8

AX = AL × operand8

mul operand16

DX:AX = AX × operand16

mul operand32

EDX:EAX = EAX × operand32

mul operand64

RDX:RAX = RAX × operand64

В AX/EAX/RAX помещается младшая часть результата, а в DX/EDX/RDX - старшая.

Если результат умножения по количеству бит больше разрядности операндов, то инструкция mul устанавливает флаг переноса CF и флаг переполнения OF. Соответственно, если мы проверим флаг переноса CF и обнаружим, что он установлен, это значит, что старшая часть помещена в регистр RDX. Пример умножения на Linux

global _start

section .text
_start:
    mov rdi, 2
    mov rax, 4
    mul rdi         ; RAX = RAX * RDI
    mov rdi, rax    ; RDI = RAX = 8
    mov rax, 60
    syscall 

Здесь в регистр RAX помещается число 4, а в регистр RDI - число 2. При выполнении инструкции mul rdi значения регистров RAX и RDI будут перемножаться, и результат помещен в регистр RAX. То есть в RAX будет число 2 * 4 = 8. Затем из RAX число копируем в регистр RDI.

Аналогичный пример на Windows:

global _start

section .text
_start:
    mov rdi, 2
    mov rax, 4
    mul rdi         ; RAX = RAX * RDI = 8 
    ret    

Возьмем чуть по сложнее пример, где результат умножения раскидан по регистрам RDX/RAX:

global _start

section .text
_start:
    mov rdi, 0xC000000000000002
    mov rax, 4
    mul rdi           ; RDX:RAX = RDI * RAX

    mov rdi, rdx    ; помещаем в RDI старшие 64 бита результата -  RDI = RDX = 3
    mov rax, 60
    syscall 

Здесь 8-байтное число 0xC000000000000002 из регистра RDI умножается на число 4. Результатом будет шестнадцатеричное число 0x03_0000000000000008 (в десятичной системе это число 55340232221128654856). Однако для этого числа требуется 66 бит (точнее 9 байт), что превышает размер регистра RAX. Поэтому старшие 2 бита помещаются в регистр RDX. Соответственно после выполнения инструкции mov rdi, rdx в регистре RDI будет число 3.

Другие формы инструкции imul

Инструкция imul также может принимать два и три операнда:

imul dest, source
imul dest, source, constant

Если инструкции передается два операнда, то она умножает первый операнд на второй и результат присваивает первому операнду:

dest = dest * source

Первый операнд - всегда регистр. Второй операнд может представлять регистр, переменную или константу. Оба операнда должны совпадать по размеру и могут быть 16-, 32- и 64-разрядными, за исключением констант, которые не могут превышать 32 бит (Если первый операнд 64-разрядный, то константы автоматически расширяются со знаком до 64 бит).

Пример умножения:

global _start

section .text
_start:
    mov rdi, 3
    imul rdi, 5     ; RDI = RDI * 5 = 3 * 5 = 15
    mov rax, 60
    syscall 

Если инструкция принимает три операнда, то умножаются втрой и третий операнд, а результат помещается в первый операнд:

dest = source * constant

Первый операнд - по прежнему регистр. Второй операнд - регистр или переменная. А третий операнд - константа. При этом операнды также должны соответствовать по разрядности, и могут быть 16-, 32- и 64-разрядными, за исключением констант, которые опять же не должны превышать 32 бит. Пример:

global _start

section .text
_start:
    mov rdx, 3
    imul rdi, rdx, 4     ; RDI = RDX * 4 = 3 * 4 = 12
    mov rax, 60
    syscall 

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850