Умножение в ассемблере: Умножение и деление в ассемблере.

Умножение и деление в ассемблере.

Умножение и деление в ассемблере. — it-black.ru Перейти к содержимому Search

Все мы знаем со школы что такое умножение и деление и конечно же в ассемблере эти команды присутствуют, и я расскажу Вам о них. В ассемблере умножение и деление для положительных и отрицательных чисел выполняются по-разному.

Умножение положительных чисел

Для умножения положительных чисел в ассемблере предназначена команда «MUL». У этой команды только один операнд — второй множитель, который должен находиться в регистре или в памяти. Местоположение первого множителя и результата задаётся неявно и зависит от размера операнда:

Размер операндаМножительРезультат
БайтALAX
СловоAXDX: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». У этой команды один операнд — делитель, который должен находиться в регистре или в памяти. Местоположение делимого, частного и остатка задаётся неявно и зависит от размера операнда:

Размер операнда
(делителя)
ДелимоеЧастноеОстаток
БайтAXALAH
СловоDX:AXAXDX

Некоторые тонкости деления:

  • Если аргументом команды 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. Эта команда также генерирует прерывание при делении на ноль или слишком большом частном.

Facebook

Twitter

  • 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`
.
Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *