Для умножения беззнаковых чисел применяется команда mul, к которой добавляется суффикс типа данных
mulq: для умножения 64-разрядных чисел
mull: для умножения 32-разрядных чисел
mulw: для умножения 16-разрядных чисел
mulb: для умножения 8-разрядных чисел
Она принимает один операнд - регистр или адрес в памяти и умножает его на значение в регистре RAX. Результат помещается в регистры RAX/RDX:
mulb operand8 # результат в AX mulw operand16 # результат в DX:AX mull operand32 # результат в EDX:EAX mulq operand64 # результат в RDX:RAX
В качестве операнда можно передавать регистр или переменную/адрес в памяти. Единственный операнд умножается на соответствующий его размеру регистр AL/AX/EAX/RAX. Результат умножения двух n-битных значений может потребовать 2×n бит. Следовательно, если операнд - 8-битное число, то для результата может потребоваться 16 бит. Аналогично, 16-битный операнд дает 32-битный результат и т.д.
mulb operand8 | AX = AL × operand8 |
mull operand16 | DX:AX = AX × operand16 |
mull operand32 | EDX:EAX = EAX × operand32 |
mulq operand64 | RDX:RAX = RAX × operand64 |
В AX/EAX/RAX помещается младшая часть результата, а в DX/EDX/RDX - старшая.
Если результат умножения по количеству бит больше разрядности операндов, то инструкция mul
устанавливает флаг переноса CF и флаг переполнения OF.
Пример использования
.globl _start .text _start: movq $2, %rdi movq $4, %rax mulq %rdi # RAX = RAX * RDI movq %rax, %rdi # RDI = RAX = 8 movq $60, %rax syscall
Здесь в регистр RAX помещается число 4, а в регистр RDI - число 2. При выполнении инструкции mulq %rdi
значения регистров RAX и RDI будут перемножаться, и результат
помещен в регистр RAX. То есть в RAX будет число 2 * 4 = 8. Затем из RAX число копируем в регистр RDI.
Возьмем чуть по сложнее пример, где результат умножения раскидан по регистрам RDX/RAX:
.globl _start .text _start: movq $0xC000000000000002, %rdi movq $4, %rax mulq %rdi # RDX:RAX = RDI * RAX movq %rdx, %rdi # помещаем в RDI старшие 64 бита результата - RDI = RDX = 3 movq $60, %rax # RAX = 60 syscall
Здесь 8-байтное число 0xC000000000000002
из регистра RDI умножается на число 4. Результатом будет шестнадцатеричное число 0x03_0000000000000008
(в десятичной системе
это число 55340232221128654856). Однако для этого числа требуется 66 бит (точнее 9 байт), что превышает размер регистра RAX. Поэтому старшие 2 бита помещаются в регистр RDX.
Соответственно после выполнения инструкции movq %rdx, %rdi
в регистре RDI будет число 3.
Для умножения чисел со знаком применяется инструкция imul, которая работает аналогично.