Tooprogram.ru

Компьютерный справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Imul в ассемблере

ProgrammWS

Все для начинающего программиста

Меню сайта

Информация

Programm.ws — это сайт, на котором вы можете почитать литературу по языкам программирования , а так-же посмотреть примеры работающих программ на С++, ассемблере, паскале и много другого..

Программирование — в обычном понимании, это процесс создания компьютерных программ.
В узком смысле (так называемое кодирование) под программированием понимается написание инструкций — программ — на конкретном языке программирования (часто по уже имеющемуся алгоритму — плану, методу решения поставленной задачи). Соответственно, люди, которые этим занимаются, называются программистами (на профессиональном жаргоне — кодерами), а те, кто разрабатывает алгоритмы — алгоритмистами, специалистами предметной области, математиками.
В более широком смысле под программированием понимают весь спектр деятельности, связанный с созданием и поддержанием в рабочем состоянии программ — программного обеспечения ЭВМ. Более точен современный термин — «программная инженерия» (также иначе «инженерия ПО»). Сюда входят анализ и постановка задачи, проектирование программы, построение алгоритмов, разработка структур данных, написание текстов программ, отладка и тестирование программы (испытания программы), документирование, настройка (конфигурирование), доработка и сопровождение.

Официальный сайт приста гидры.

Приложение. Система команд процессоров Intel

IMUL Умножение целых чисел со знаком

Команда IMUL выполняет умножение целого числа со знаком, находящегося в регистре AL (в случае умножения на байт) или АХ (в случае умножения на слово), на операнд-источник (целое число со знаком). Размер произведения в два раза больше размера сомножителей.
Для однобайтовых операций один из сомножителей помещается в регистр AL; после выполнения операции произведение записывается в регистр АХ.
Для двухбайтовых операций один из сомножителей помещается в регистр АХ; после выполнения операции произведение записывается в регистры DX:AX (в DX — старшая часть, в АХ — младшая).
В качестве операнда-сомножителя команды imul можно указывать регистр (кроме сегментного) или ячейку памяти; не допускается умножение на непосредственное значение. Команда воздействует на флаги OF и CF. Если АН или DX представляют собой просто знаковое расширение AL или АХ, соответственно (т.е. результат умножения со знаком верен), OF и CF сбрасываются в 0; в противном случае (результат со знаком не помещается в АХ или DX:AX) OF и CF устанавливаются в 1.

mov AL,5 ;Первый сомножитель
mov BL,3 ;Второй сомножитель
imul BL ;AX=000Fh (произведение)

mov AX,256 ;Первый сомножитель
mov BX,256 ;Второй сомножитель
imul BX ;DX=0001h, AX=0000h
;(число 65536)

Допустимо использование 32-битовых операндов и дополнительных режимов адресации 32-разрядных процессоров. Имеются также варианты команды с двумя и тремя операндами.

Для команды imul с одним операндом второй сомножитель должен располагаться в AL, АХ или ЕАХ. Процессор выбирает размерность второго сомножителя, исходя из размерности первого, указанного в качестве операнда. 16-, 32- или 64-битовый знаковый результат помещается в регистры АХ, DX:AX или EDX:EAX, соответственно. Если после операции умножения содержимое АН, DX или EDX является лишь знаковым расширением AL, АХ или ЕАХ, соответственно, то флаги CF и OF сбрасываются в 0. В противном случае они устанавливаются в 1.
Для команды imul с двумя операндами их произведение записывается в первый операнд; второй операнд не изменяется. В качестве первого операнда могут выступать 16- или 32-разрядные регистры общего назначения; в качестве второго операнда — 16- или 32-разрядные регистры общего назначения, 16- или 32-битовые ячейки памяти или непосредственное значение. Оба операнда должны иметь один размер. Если результат умножения помещается в первый операнд, флаги CF и OF сбрасываются в 0. В противном случае они устанавливаются в 1.
Для команды imul с тремя операндами произведение второго и третьего операндов записывается в первый операнд. В качестве первого операнда могут выступать 16- или 32-разрядные регистры общего назначения; в качестве второго операнда — 16- или 32-разрядные регистры общего назначения или 16- или 32-битовые ячейки памяти; в качестве третьего операнда — только непосредственное значение. Два первых операнда должны иметь один размер. Если результат умножения помещается в первый операнд, флаги CF и OF сбрасываются в 0. В противном случае они устанавливаются в 1.

mov EAX,-1 ;Первый сомножитель
mov ESI,100000000 ;Второй сомножитель
imul ESI ;EDX=FFFFFFFFh,
;EAX=FA0AlF00h
;Результат=-100000000

;В полях данных
ор2 dd 100h ;Первый сомножитель
; В программном сегменте
mov EAX,400000h ;Второй сомножитель
imul EAX,op2 ;EAX=40000000h
Пример 3
mov BX,300h
imul АХ,ВХ,4 ;AX=300h*4=0C00h

Команда MUL

Что такое JavaScript

Если вы интересуетесь программированием вообще, и сайтостроением в частности, то вы наверняка слышали слово JavaScript. И, если вы до сих пор не узнали толком, что же это такое, то пришло время сделать это. Подробнее.

Инструкция MUL в Ассемблере выполняет умножение без знака. Понять работу команды MUL несколько сложнее, чем это было для команд, рассмотренных ранее. Но, надеюсь, что я помогу вам в этом разобраться.

Итак, синтаксис команды MUL такой:

Выглядит всё очень просто. Однако эта простота обманчива.

Прежде чем разобраться в подробностях работы этой инструкции, давайте посмотрим, что может быть ЧИСЛОМ.

ЧИСЛОМ может быть один из следующих:

  • Область памяти (MEM)
  • Регистр общего назначения (REG)

Эта команда не работает с сегментными регистрами, а также не работает непосредственно с числами. То есть вот так

MUL 200 ; неправильно

А теперь алгоритм работы команды MUL:

  • Если ЧИСЛО — это БАЙТ, то AX = AL * ЧИСЛО
  • Если ЧИСЛО — это СЛОВО, то (DX AX) = AX * ЧИСЛО

Вот такая немного сложноватая команда. Хотя сложно это с непривычки. Сейчас мы разберём всё “по косточкам” и всё станет ясно.

Для начала обратите внимание, что инструкция MUL работает либо с регистром АХ, либо с регистром AL. То есть перед выполнением этой команды нам надо записать в регистр АХ или в регистр AL значение, которое будет участвовать в умножении. Сделать это можно, например, с помощью уже известной нам команды MOV.

Затем мы выполняем умножение, и получаем результат либо в регистр АХ (если ЧИСЛО — это байт), либо в пару регистров DX и AX (если ЧИСЛО — это слово). Причём в последнем случае в регистре DX будет старшее слово, а в регистре AX — младшее.

А теперь, чтобы совсем всё стало понятно, разберём пару примеров — с байтом и словом.

Пример умножения в Ассемблере

Итак, например, нам надо умножить 150 на 250. Тогда мы делаем так:

Обратите внимание, что нам приходится два раза использовать команду MOV, так как команда MUL не работает непосредственно с числами, а только с регистрами общего назначения или с памятью.

После выполнения этого кода в регистре АХ будет результат умножения чисел 150 и 250, то есть число 37500 (927С в шестнадцатеричной системе).

Теперь попробуем умножить 10000 на 5000.

В результате мы получили довольно большое число, которое, конечно, не поместится в слово. Поэтому для результата используются два регистра — DX и AX. В нашем примере в регистре DX, будет число 762 (02FA — в шестнадцатеричной системе), а в регистре АХ — число 61568 (F080 — в шестнадцатеричной системе). А если рассматривать их как одно число (двойное слово), где в старшем слове 762, а в младшем — 61568, то это и будет 50000000 (2FAF080 — в шестнадцатеричной системе).

Если не верите — может перевести всё это в двоичное число и проверить.

После выполнения команды MUL состояния флагов ZF, SF, PF, AF не определены и могут быть любыми.

А если старшая секция результата (регистр AH при умножении байтов или регистр DX при умножении слов) равна нулю, то

Иначе эти флаги либо не равны, либо равны 1.

В конце как обычно расскажу, почему эта команда ассемблера называется MUL. Это сокращение от английского слова MULTIPLY, которое можно перевести как “умножить, умножать”.

проблема в понимании инструкций mul & imul языка ассемблера

  • если операнд имеет размер байта, он умножается на байт в AL регистрация и результат сохраняется в 16 бит AX.
  • если источник 16-разрядный, он умножается на слово в AX и 32-разрядный результат хранится в DX: AX.

Вопрос 1: почему DX: AX ? Почему он не может хранить в EAX / EDX?

imul — это действительно сбивает с толку

у меня проблемы с пониманием таблицы.

Вопрос 2: во 2-й записи таблицы. Опять же, почему DX: AX. Почему не EAX или EDX?

Теперь рассмотрим следующий код фрагмент:

Вопрос 3: его previsously сказал, что The notation EDX:EAX means to think of the EDX and EAX registers as one 64 bit register with the upper 32 bits in EDX and the lower bits in EAX. таким образом, ответ также хранится в edx, верно? в приведенном выше коде мы не рассматривали EDX, мы просто ссылаемся на EAX Как это все еще работает?

Q4: у меня проблема с остальными записями в таблице. в худшем случае результат умножения двух N разрядных чисел (n = 8/16/32 бит) составляет 2n бит. Почему его хранение результата двух 16/32 бит умножения приводит к регистру тот же самый размер?

5 ответов

Q1/Q2: набор инструкций x86 сохраняет свою 16-разрядную историю. При выполнении 16-битного умножения ответ сохраняется в DX: AX. Так оно и есть, потому что так было в 16-битной стране.

Q3: код, который вы показали, имеет ошибку, если вы пытаетесь вычислить квадрат числа больше 2^16, потому что код игнорирует высокие 32 бита результата, хранящегося в edx .

Q4: я думаю, вы, возможно, неправильно читаете таблицу. 8-разрядные умножения хранятся в 16-разрядном результат; 16-разрядные умножения хранятся в 32-разрядном результате; 32-разрядные умножения хранятся в 64-разрядном результате. На какую конкретно линию вы ссылаетесь?

существует множество различных вариантов инструкции imul. И что еще хуже, они работают по-разному, если вы пишете 16-битный код против 32-битного кода.

вариант, на который вы наткнулись, — это 16-битное умножение. Он умножает регистр AX на все, что вы передаете в качестве аргумента imul, и сохраняет результат в DX:AX.

один 32-битный вариант работает как 16-битное умножение, но записывает регистр в EDX: EAX. Использовать это вариант все, что вам нужно сделать, это использовать 32-битный аргумент.

в 32-битном коде вы также можете написать imul в форме трех операндов. Это делает его более гибким и легким в работе. В этом варианте вы можете свободно выбирать регистр назначения и аргументы, но результат будет только 32 бита. Этот вариант imul не существует для 16-битного кода btw.

Q1/Q2: почему DX: AX ? Почему он не может хранить в EAX / EDX?

как говорили другие, это только для обратной совместимости. Оригинал (i)mul инструкции от 16-битного x86, который пришел долго до появления 32-разрядного набора инструкций x86, поэтому они не могли сохранить результат в eax/edx с не было электронного регистра.

Вопрос 3: в выше кода мы не рассматривали EDX, мы просто ссылаемся на EAX, как это все еще работает?

вы ввели небольшие значения, которые не вызывают переполнения результата, поэтому вы не видели различий. Если вы используете достаточно большие значения (>=16 бит), вы увидите, что EDX != 0 и результат печати будет неверным.

Q4: как получилось, что он хранит результат двух 16/32 бит умножения в регистре одинакового размера себя?

дело не в том, что результат все тот же размер как операнды. умножение двух n-разрядных значений всегда приводит к 2n-разрядному значению. Но в imul r16, r/m16[, imm8/16] и их 32/64-разрядные аналоги высокие N-разрядные результаты отбрасываются. Они используются, когда вам нужно только понизьте 16/32/64 бита результата (т. е. для расширяющегося умножения), или когда вы можете убедиться, что результат не переполнение.

  • форма двух операндов — с этой формой целевой операнд (первый операнд) умножается на исходный операнд (второй операнд). Операнд назначения является регистром общего назначения, а исходный операнд-непосредственным значением, регистром общего назначения или хранилищем памяти. промежуточный продукт (в два раза больше входного операнда) усекается и сохраняется в месте назначения операнда.
  • [. То же самое для формы трех операндов]

современные компиляторы в настоящее время почти исключительно используют мульти-операнд imul как для знаковых, так и для беззнаковых умножений, потому что

  • нижние биты всегда одно и то же в обоих случаях, и в C умножение двух переменных генерирует результат одинакового размера ( int x int → int , long x long → long . ) которые подходят imul операнды красиво. Единственный способ заставить компиляторы испускать один операнд mul или imul is использование типа в два раза больше размера регистра
  • это очень редко, чтобы увидеть умножение, где результат шире, чем размер регистра, как int64_t a; __int128_t p = (__int128_t)a * b; так один операнд (i)mul редко
  • расчет только нижние биты будут быстрее получение полного результата.
  • гораздо больше гибкости в использовании из-за различных форм imul инструкция
    • в форме 2-операнда вам не нужно сохранять / восстанавливать EDX и EAX
    • форма 3-операнда далее позволяет выполнять неразрушающее умножение
  • современные процессоры часто оптимизируются для мульти-операндных версий imul (поскольку современные компиляторы в настоящее время почти исключительно используется мульти-операнд imul как для знаковых, так и для беззнаковых умножений) так они будут быстрее, чем один операнд (i)mul

Q1 / Q2: я думаю, что причина историческая. До 32-разрядный вариант, нет еах или edX. 32-разрядная функциональность была добавлена для обратной совместимости.

Q3: биты низкого порядка будут находиться в eax. Это единственные, о которых вы заботитесь, если нет переполнения в высокие биты.

Q4: определенно нечетная таблица. Но я думаю, ты понимаешь.

A1: mul первоначально присутствовал на процессорах 8086/8088/80186/80286, которые не имели регистров E** (E для расширенных, т. е. 32-разрядных).

А2: См. A1.

поскольку моя работа в качестве программиста ассемблерного языка перешла в семейство Motorola 680×0 до того, как эти 32-битные Intels стали обычным явлением, я остановлюсь на этом : -)

Ассемблер. Арифметические инструкции

Обновл. 20 Окт 2019 |

В этом уроке мы будем разбираться с арифметическими инструкциями в ассемблере на примере INC, DEC, ADD, SUB и пр.

Инструкция INC

Инструкция INC (от англ. «INCREMENT») используется для увеличения операнда на единицу. Она работает с одним операндом, который может находиться либо в регистре, либо в памяти.

Синтаксис инструкции INC:

Операндом место_назначения может быть 8-битный, 16-битный или 32-битный операнд.

Инструкция DEC

Инструкция DEC (от англ. «DECREMENT») используется для уменьшения операнда на единицу. Она работает с одним операндом, который может находиться либо в регистре, либо в памяти.

Синтаксис инструкции DEC:

Операндом место_назначения может быть 8-битный, 16-битный или 32-битный операнд.

Инструкции ADD и SUB

Инструкции ADD и SUB используются для выполнения простого сложения/вычитания двоичных данных размером в byte, word и doubleword, то есть для сложения или вычитания 8-битных, 16-битных или 32-битных операндов, соответственно.

Синтаксис инструкций ADD и SUB:

ADD/SUB место_назначения, источник

Инструкции ADD/SUB могут выполняться между:

регистром и регистром;

памятью и регистром;

регистром и памятью;

памятью и константами.

Однако, как и другие инструкции, операции типа память-в-память невозможны с использованием инструкций ADD/SUB. Операции ADD или SUB устанавливают или сбрасывают флаги переполнения и переноса.

В следующем примере мы спрашиваем у пользователя два числа, сохраняем их в регистрах EAX и EBX, затем выполняем операцию сложения, сохраняем результат в ячейке памяти res и выводим его на экран:

Результат выполнения программы выше:

Enter a digit:
3
Please enter a second digit:
4
The sum is:
7

Ниже рассмотрен пример, в котором, за счёт того, что значения переменных для арифметических выражений прописаны в самом коде программы, можно получить код программы короче и проще:

Результат выполнения программы выше:

Инструкции MUL и IMUL

Есть две инструкции для умножения двоичных данных:

инструкция MUL (от англ. «MULTIPLY») обрабатывает данные unsigned;

инструкция IMUL (от англ. «INTEGER MULTIPLY») обрабатывает данные signed.

Обе инструкции влияют на флаги переноса и переполнения.

Синтаксис инструкций MUL/IMUL:

Множимое в обоих случаях будет в аккумуляторе, в зависимости от размера множимого и множителя, и результат умножения также сохраняется в двух регистрах, в зависимости от размера операндов.

Рассмотрим 3 разных сценария:

Сценарий №1: Когда перемножаются 2 значения типа byte — множимое находится в регистре AL, а множителем является значение типа byte в памяти или в другом регистре. Результат произведения находится в AX. Старшие 8 бит произведения хранятся в AH, а младшие 8 бит — хранятся в AL:

Сценарий №2: Когда перемножаются 2 значения типа word — множимое должно быть в регистре AX, а множителем является значение типа word в памяти или в другом регистре. Например, для такой инструкции, как MUL DX , вы должны сохранить множитель в DX, а множимое — в AX. В результате получится значение типа doubleword для которого понадобятся два регистра. Часть высшего порядка (крайняя слева) сохраняется в DX, а часть нижнего порядка (крайняя справа) — сохраняется в AX:

Сценарий №3: Когда перемножаются 2 значения типа doubleword — множимое должно находится в EAX, а множителем является значение типа doubleword, хранящееся в памяти или в другом регистре. Результат умножения сохраняется в регистрах EDX и EAX. Биты старшего порядка сохраняются в регистре EDX, а биты младшего порядка — сохраняются в регистре EAX:

Читать еще:  Единицей измерения в системе си является
Ссылка на основную публикацию
Adblock
detector