Ассемблер
Как работает MUL в ассемблере
MUL в x86-ассемблере выполняет беззнаковое умножение. У этой инструкции есть важная особенность: один операнд задается явно, а второй берется из аккумулятора автоматически. Результат получается шире исходных операндов и записывается в пару регистров: AX, DX:AX, EDX:EAX или RDX:RAX в зависимости от размера
Пример для 8 бит
mov al, 5
mov bl, 3
mul bl
Здесь mul bl умножает AL на BL. Результат попадает в AX
После выполнения:
AX = 15
Даже если оба числа 8-битные, результат хранится в 16-битном AX, потому что произведение может не поместиться в 8 бит
Пример для 32 бит
mov eax, 1000
mov ebx, 20
mul ebx
Инструкция умножает EAX на EBX. Результат попадает в пару:
EDX:EAX
Если результат помещается в EAX, EDX будет нулевым. Если не помещается, старшая часть окажется в EDX
Таблица размеров
| Размер операнда | Скрытый операнд | Явный операнд | Результат |
|---|---|---|---|
| 8 бит | AL |
r/m8 | AX |
| 16 бит | AX |
r/m16 | DX:AX |
| 32 бит | EAX |
r/m32 | EDX:EAX |
| 64 бит | RAX |
r/m64 | RDX:RAX |
Это ключ к пониманию mul: результат почти всегда нужно искать не только в одном регистре
MUL и IMUL
MUL — беззнаковое умножение. Если числа знаковые, используйте IMUL. Например, для отрицательных значений mul даст не тот смысл, который ожидают при обычной signed-арифметике
Как проверить результат в отладчике
После выполнения mul смотрите пару регистров. Для 32-битного варианта это EDX:EAX. Если вы умножаете маленькие числа, EDX часто будет равен нулю. Если число большое, старшая часть результата попадет в EDX
Хорошее упражнение: сначала умножьте 1000 * 20, потом число, которое не помещается в 32 бита. Так сразу станет видно, почему результат mul шире одного регистра
Флаги после MUL
MUL влияет на CF и OF. Если старшая половина результата не нулевая, эти флаги устанавливаются. Это признак, что результат не поместился в младшую часть
Для 32-битного умножения: если EDX не ноль, произведение не поместилось только в EAX
Частые ошибки
Ждут два явных операнда
В форме mul ebx второй операнд уже скрыт в eax. Это не mul eax, ebx
Не смотрят старшую часть результата
После 32-битного mul проверяйте EDX:EAX, а не только EAX
Используют MUL для отрицательных чисел
Для знакового умножения нужен imul
Не очищают регистры перед расчетом
Перед умножением убедитесь, что в аккумуляторе именно то значение, которое нужно умножить
Мини-пример проверки
mov eax, 4000000000
mov ebx, 2
mul ebx
Результат не поместится в 32 бита, поэтому важна старшая часть в EDX. Если смотреть только EAX, вы увидите обрезанное значение
Что почитать дальше по ассемблеру
Если нужен общий маршрут по теме, откройте рубрику ассемблеру. Для соседних задач пригодятся эти разборы:
- CMP в ассемблере: как работает сравнение
- JP в ассемблере: как работает переход
- Как работает CMP в ассемблере
- Как работает DIV в ассемблере
Как проверить результат на практике
Для ассемблера важно сначала понять, под какую среду написан пример: DOSBox/TASM, Linux x64/NASM, Visual Studio/MASM или микроконтроллер. Один и тот же смысл может записываться разным синтаксисом, поэтому не переносите команды между средами вслепую. Создайте отдельную папку для примера, сохраните файл с расширением .asm, выполните сборку именно тем инструментом, который указан в уроке, и сравните вывод или состояние регистров с ожидаемым результатом
Если пример не собирается, читайте первую ошибку ассемблера: обычно она указывает на строку, неизвестную инструкцию, неверную метку, неправильную секцию или конфликт синтаксиса. Исправляйте одну ошибку за раз. В ассемблере это особенно важно, потому что маленькая опечатка в метке, регистре или размере операнда может полностью изменить поведение программы