Умножение и деление в ассемблере.
Умножение и деление в ассемблере. — it-black.ru Перейти к содержимому SearchВсе мы знаем со школы что такое умножение и деление и конечно же в ассемблере эти команды присутствуют, и я расскажу Вам о них. В ассемблере умножение и деление для положительных и отрицательных чисел выполняются по-разному.
Умножение положительных чисел
Для умножения положительных чисел в ассемблере предназначена команда «MUL». У этой команды только один операнд — второй множитель, который должен находиться в регистре или в памяти. Местоположение первого множителя и результата задаётся неявно и зависит от размера операнда:
| Размер операнда | Множитель | Результат |
|---|---|---|
| Байт | AL | AX |
| Слово | AX | DX:AX |
Некоторые тонкости умножения:
- Если аргументом команды mul является 1-байтовый регистр (например mul bl), то значение этого регистра bl умножится на значение регистра al, а результат запишется в регистр ax, и так будет всегда, независимо от того, какой 1-байтовый регистр взять.
bl*al = ax - Если аргументом является регистр из 2 байт (например mul bx), то значение в регистре bx умножится на значение, хранящееся в регистре ax, а результат умножения запишется в регистр eax. bx*ax = eax
- Если аргументом является регистр из 4 байт (например mul ebx), то значение в регистре ebx умножится на значение, хранящееся в регистре eax, а результат умножения запишется в 2 регистра: edx и eax. ebx*eax = edx:eax
Умножение отрицательных чисел
Для умножения чисел со знаком предназначена команда «IMUL». Эта команда имеет три формы, различающиеся количеством операндов:
- С одним операндом — форма, аналогичная команде MUL. В качестве операнда указывается множитель. Местоположение другого множителя и результата определяется по таблице.
- С двумя операндами — указываются два множителя. Результат записывается на место первого множителя. Старшая часть результата в этом случае игнорируется. Эта форма команды не работает с операндами размером 1 байта.

- С тремя операндами — указывается положение результата, первого и второго множителя. Второй множитель должен быть непосредственным значением. Результат имеет такой же размер, как первый множитель, старшая часть результата игнорируется. Это форма тоже не работает с однобайтными множителями.
Деление положительных чисел
Деление целых двоичных чисел — это всегда деление с остатком. По аналогии с умножением, размер делителя, частного и остатка должен быть в 2 раза меньше размера делимого. Деление положительных чисел осуществляется с помощью команды «DIV». У этой команды один операнд — делитель, который должен находиться в регистре или в памяти. Местоположение делимого, частного и остатка задаётся неявно и зависит от размера операнда:
| Размер операнда (делителя) | Делимое | Частное | Остаток |
|---|---|---|---|
| Байт | AX | AL | AH |
| Слово | DX:AX | AX | DX |
Некоторые тонкости деления:
- Если аргументом команды div является 1-байтовый регистр (например div bl), то значение регистра ax поделится на значение регистра bl, результат от деления запишется в регистр al, а остаток запишется в регистр ah.
ax/bl = al, ah - Если аргументом является регистр из 2 байт (например div bx), то процессор поделит число, старшие биты которого хранит регистр dx, а младшие ax на значение, хранящееся в регистре bx. Результат от деления запишется в регистр ax, а остаток запишется в регистр dx. (dx,ax)/bx = ax, dx
- Если аргументом является регистр из 4 байт (например div ebx), то процессор аналогично предыдущему варианту поделит число, старшие биты которого хранит регистр edx, а младшие eax на значение, хранящееся в регистре ebx. Результат от деления запишется в регистр eax, а остаток запишется в регистр edx. (edx,eax)/ebx = eax, edx
Деление отрицательных чисел
Для деления отрицательных чисел предназначена команда IDIV. Единственным операндом является делитель. Местоположение делимого и частного определяется также, как для команды DIV. Эта команда также генерирует прерывание при делении на ноль или слишком большом частном.
- Виктор Черемных
- 13 августа, 2017
- No Comments
Группа в VK
Обнаружили опечатку?
Сообщите нам об этом, выделите текст с ошибкой и нажмите Ctrl+Enter, будем очень признательны!
Свежие статьи
Облако меток
Похожие статьи
Команды работы с битами.

Работать с отдельными битами операндов можно, используя логические операции и сдвиги. Также в системе команд x86 существуют специальные команды для работы с битами: это команды
Основы создания макросов в Assembler.
Макросы — это шаблоны для генерации кода. Один раз создав макрос, можно использовать его во многих местах в коде программы. Макросы делают процесс программирования на
Синтаксис объявления меток.
Метка в ассемблере – это символьное имя, обозначающее ячейку памяти, которая содержит некоторую команду. Метка может содержать следующие символы: Буквы (от A до Z и
Локальные переменные.
Локальные переменные в Assembler используются для хранения промежуточных результатов во время выполнения процедуры. В отличие от глобальных, эти переменные являются временными и создаются при запуске
Instagram Vk Youtube Telegram OdnoklassnikiПолезно знать
Рубрики
Авторы
Команда MUL
|
Лучшие книги по Ассемблеру
Сделал подборку не новых, но проверенных книг по программированию на языке ассемблера. |
Инструкция MUL в Ассемблере выполняет умножение без знака. Понять работу команды MUL несколько сложнее, чем это было для команд, рассмотренных ранее. Но, надеюсь, что я помогу вам в этом разобраться.
Итак, синтаксис команды MUL такой:
MUL ЧИСЛО
Выглядит всё очень просто. Однако эта простота обманчива.
Прежде чем разобраться в подробностях работы этой инструкции, давайте посмотрим, что может быть ЧИСЛОМ.
ЧИСЛОМ может быть один из следующих:
- Область памяти (MEM)
- Регистр общего назначения (REG)
Эта команда не работает с сегментными регистрами, а также не работает непосредственно с числами.
То есть вот так
MUL 200 ; неправильно
делать нельзя.
А теперь алгоритм работы команды MUL:
- Если ЧИСЛО — это БАЙТ, то AX = AL * ЧИСЛО
- Если ЧИСЛО — это СЛОВО, то (DX AX) = AX * ЧИСЛО
Вот такая немного сложноватая команда. Хотя сложно это с непривычки. Сейчас мы разберём всё “по косточкам” и всё станет ясно.
Для начала обратите внимание, что инструкция MUL работает либо с регистром АХ, либо с регистром AL. То есть перед выполнением этой команды нам надо записать в регистр АХ или в регистр AL значение, которое будет участвовать в умножении. Сделать это можно, например, с помощью уже известной нам команды MOV.
Затем мы выполняем умножение, и получаем результат либо в регистр АХ (если ЧИСЛО — это
байт), либо в пару регистров DX и AX (если ЧИСЛО — это слово). Причём в последнем
случае в регистре DX будет старшее слово, а в регистре AX — младшее.
А теперь, чтобы совсем всё стало понятно, разберём пару примеров — с байтом и словом.
Итак, например, нам надо умножить 150 на 250. Тогда мы делаем так:
MOV AL, 150 ; Первый множитель в регистр AL MOV BL, 250 ; Второй множитель в регистр BL MUL BL ; Теперь АХ = 150 * 250 = 37500
Обратите внимание, что нам приходится два раза использовать команду MOV, так как команда MUL не работает непосредственно с числами, а только с регистрами общего назначения или с памятью.
После выполнения этого кода в регистре АХ будет результат умножения чисел 150 и 250, то есть число 37500 (927С в шестнадцатеричной системе).
Теперь попробуем умножить 10000 на 5000.
MOV AX, 10000 ; Первый множитель в регистр AX MOV BX, 5000 ; Второй множитель в регистр BX MUL BX ; Теперь (DX АХ) = 10000 * 5000 = 50000000
В результате мы получили довольно большое число, которое, конечно, не поместится в
слово.
Поэтому для результата используются два регистра — DX и AX. В нашем примере
в регистре DX, будет число 762 (02FA — в шестнадцатеричной системе), а в регистре
АХ — число 61568 (F080 — в шестнадцатеричной системе). А если рассматривать их как
одно число (двойное слово), где в старшем слове 762, а в младшем — 61568, то это и будет 50000000 (2FAF080 — в шестнадцатеричной системе).
Если не верите — может перевести всё это в двоичное число и проверить.
Теперь о флагах.
После выполнения команды MUL состояния флагов ZF, SF, PF, AF не определены и могут быть любыми.
А если старшая секция результата (регистр AH при умножении байтов или регистр DX при умножении слов) равна нулю, то
CF = OF = 0
Иначе эти флаги либо не равны, либо равны 1.
В конце как обычно расскажу, почему эта команда ассемблера называется MUL.
Это сокращение от английского слова MULTIPLY, которое можно перевести как “умножить, умножать”.
|
Подписаться на Дзен-канал
Вступить в группу «Основы программирования» Подписаться на рассылки по программированию |
|
Первые шаги в программирование
Главный вопрос начинающего программиста – с чего начать? Вроде бы есть желание, но иногда «не знаешь, как начать думать, чтобы до такого додуматься». У человека, который никогда не имел дело с информационными технологиями, даже простые вопросы могут вызвать большие трудности и отнять много времени на решение. Подробнее… |
x86 — функция MUL в ассемблере
Они называются инструкциями и определяют операции , которые должны выполняться процессором.
mov — это мнемоника для mov e, а mul — мнемоника для mul tiply. Другие общие инструкции включают добавить , sub и div . Я надеюсь, вы сможете понять, какую операцию они определяют!
Большинство инструкций принимают два параметра. На техническом жаргоне их часто называют 9.0003 операндов . Первый (слева) — это пункт назначения , а второй (справа) — источник . Таким образом, в случае mov bx, 5 это перемещает буквальное значение 5 в регистр назначения bx . Порядок этих параметров, конечно, имеет значение, потому что вы не можете переместить содержимое регистра bx в буквальное значение 5 !
Инструкция mul немного странная, потому что некоторые из ее операндов являются неявными. То есть они явно не указаны как параметры. Для mul , операнд назначения жестко запрограммирован как регистр x .
Исходный операнд — это тот, который вы передаете в качестве параметра: это может быть либо регистр, либо ячейка памяти.
Таким образом, вы можете представить, что mul cx означает mul ax, cx , но вы не напишите это так, потому что регистр назначения ax является неявным.
Теперь инструкция mul дает процессору команду умножить операнд-адресат на операнд-источник и сохранить результат в адресате. В коде вы можете представить, что mul cx преобразуется в ax = ax * cx . И теперь вы должны увидеть проблему: вы не инициализировали содержимое регистра x , поэтому вы умножаете 10 (значение, которое вы поместили в cx ) на тот мусор, который остался в x . Таким образом, результат бессмысленен!
Если вы действительно хотите сделать 5 * 10, то вам достаточно изменить один символ в вашем коде:
mov ax, 5 ; топор = 5 мов сх, 10 ; сх = 10 мул сх ; топор = топор * сх; на самом деле dx:ax = ax * cx
Результат будет сохранен в x , который является неявным регистром назначения.
Ну, технически результат будет сохранен в dx:ax . Это пара регистров , и это означает, что старшая часть результата будет сохранена в dx , а младшая часть результата будет сохранена в x . Зачем это дополнительное усложнение? Потому что умножение двух 16-битных значений может привести к значению, превышающему 16 бит! Возврат полного результата умножения в 9Пара 0003 16-битных регистров позволяет инструкции mul возвращать 32-битный результат. Однако, когда вы только учитесь, вам не нужно беспокоиться об этом. Вы можете просто игнорировать возможность переполнения и извлечь нижнюю часть результата из x . (Но помните, что 16-битный mul перезаписывает dx , хотите вы этого или нет. На 386 и более поздних версиях вы можете использовать imul axe, cx , чтобы действительно сделать ax *= cx , не тратя время на запись dx .)
И хотя я уверен, что это всего лишь игрушечный пример, на самом деле нет причин писать код , который умножает две константы вместе.
Это можно сделать во время сборки, либо используя калькулятор и жестко закодировав значение, либо записав умножение констант символически и позволив вашему ассемблеру выполнить вычисления. То есть mov ax, 50 . Или пусть ваш ассемблер сделает это за вас с mov ax, 5 * 10 . Но, как я уже сказал, я уверен, что вы уже знали это!
Если ничего не помогло, обратитесь к документации за инструкциями, которые вызывают у вас затруднения. Вы почти всегда можете найти это в Интернете, погуглив название инструкции и «x86». Например, документацию по mul можно найти здесь, а также на нескольких других сайтах. Эта информация может быть довольно сложной, но, приложив немного усилий, вы сможете извлечь нужную информацию. Вы также найдете много другой полезной информации и ссылок в вики по тегам x86.
, но по какой-то причине я не вижу изменения регистров, когда отмечена функция MUL.
Я также должен отметить, что если вы используете отладчик для пошагового выполнения вашего кода, текущая помеченная/выделенная строка — это строка, которая около для выполнения.
Он еще не выполнен, поэтому его влияние на регистры, память и т. д. еще не будет видно. Вы должны перешагнуть инструкцию, чтобы метка/выделение было на следующей строке, и тогда вы увидите эффекты предыдущей (только что выполненной) инструкции.
Если вы поняли мое объяснение выше, после инструкции mul вы должны увидеть изменение содержимого регистров ax и dx . Вы также увидите изменение флагов и указателя инструкций, если ваш отладчик показывает какой-либо из них. Больше ничего не должно измениться! (Запись справочного руководства Intel для mul не перечисляет никаких других эффектов на архитектурное состояние машины.)
x86 — как выполнить умножение в сборке x8086, но без команды mul
Выполнение умножения без использования инструкции mul достаточно ясно, но сказать, что вы можете использовать только инструкции shl , shr , rol и ror , недостаточно для решения этой задачи.
В качестве примера см. приведенную ниже подпрограмму, которая умножает без использования инструкции mul :
; IN (al=первое число [0,9], ah=второе число [0,9]) OUT (ax=произведение [0,81]) МалыйМул: мов [$+6], аль ; Это перезаписывает операнд по умолчанию AAD. мов аль, 0 аад ; -> AX является продуктом рет
и с помощью
добавитьиподможно сделать эту программу?
Да, используя повторное добавление , и пока вы не ожидаете , используйте только , добавьте и под , потому что вам всегда понадобится хотя бы какая-то инструкция ветвления для создания цикла. И даже если бы вы избегали создания цикла посредством развертывания, вам все равно пришлось бы тестировать и переходить при каком-то условии выхода.
пример: 5 * 3 --> 0 + 5 + 5 + 5
<--- 3x --->
; IN (al=первое число [0,9], bl=второе число [0,9]) OUT (cl=произведение [0,81])
МалыйМул:
саб кл, кл ; Устанавливает CL=0
.
a: добавить cl, al
саб бл, 1
jnz .а ; Прыгает БЛ-1 раз (возможно 255 раз!)
рет
- Если когда-либо второе число в BL было нулем, то этот простой код не работает! то этот простой код будет очень неэффективно повторяться 256 раз! Тем не менее, он даст правильный результат (равный 0)
- В качестве оптимизации мы можем выбрать наименьшее из двух чисел для управления циклом. Меньше итераций — это хорошо.
; IN (al=первое число [0,9], bl=второе число [0,9]) OUT (cl=произведение [0,81])
МалыйМул:
саб кл, кл ; Устанавливает CL=0
смп бл, ал
jbe .b
хчг бл, ал
jmp .b
.a: добавить cl, al
.b: sub bl, 1
джнс .а ; Прыгает BL раз
рет
Простая версия алгоритма сдвига и добавления :
; IN (al=первое число [0,9], bl=второе число [0,9]) OUT (cl=произведение [0,81]) МалыйМул: саб кл, кл ; Устанавливает CL=0 джмп .с .a: добавить cl, al .б: шл ал, 1 ; Удваивает AL, то же, что и `ADD AL, AL` .

bl*al = ax
ax/bl = al, ah
a: добавить cl, al
саб бл, 1
jnz .а ; Прыгает БЛ-1 раз (возможно 255 раз!)
рет
