возможна ли такая операция sub ax dl
Возможна ли такая операция sub ax dl
7.1. Сложение и вычитание.
7.1.1. ADD – команда для сложения двух чисел. Она работает как с числами со знаком, так и без знака.
Логика работы команды:
По сути дела, это – команда сложения с присвоением, аналогичная принятой в языке C / C ++:
Операнды должны иметь одинаковый размер. Результат помещается на место первого операнда.
После выполнения команды изменяются флаги, по которым можно определить характеристики результата:
add dx,cx ;DX = DX + CX
add dx,cl ;Ошибка: разный размер операндов.
Логика работы команды:
По сути дела, это – команда вычитания с присвоением, аналогичная принятой в языке C / C ++:
Операнды должны иметь одинаковый размер. Результат помещается на место первого операнда.
На самом деле вычитание в процессоре реализовано с помощью сложения. Процессор меняет знак второго операнда на противоположный, а затем складывает два числа.
sub b x,cl ;Ошибка: разный размер операндов.
7.1.3. Инкремент и декремент. Очень часто в программах используется операция прибавления или вычитания единицы. Прибавление единицы называется инкрементом, а вычитание — декрементом. Для этих операций существуют специальные команды процессора: INC и DEC. Эти команды не изменяют значение флага CF.
Эти команды содержит один операнд и имеет следующий синтаксис:
Логика работы команд:
7.1.4. NEG – команда для изменения знака операнда.
Логика работы команды:
7.2. Сложение и вычитание с переносом.
В системе команд процессоров x86 имеются специальные команды сложения и вычитания с учётом флага переноса (CF). Для сложения с учётом переноса предназначена команда ADC, а для вычитания — SBB. В общем, эти команды работают почти так же, как ADD и SUB, единственное отличие в том, что к младшему разряду первого операнда прибавляется или вычитается дополнительно значение флага CF.
Они позволяют выполнять сложение и вычитание многобайтных целых чисел, длина которых больше, чем разрядность регистров процессора (в нашем случае 16 бит). Принцип программирования таких операций очень прост — длинные числа складываются (вычитаются) по частям. Младшие разряды складываются(вычитаются) с помощью обычных команд ADD и SUB, а затем последовательно складываются(вычитаются) более старшие части с помощью команд ADC и SBB. Так как эти команды учитывают перенос из старшего разряда, то мы можем быть уверены, что ни один бит не потеряется. Этот способ похож на сложение(вычитание) десятичных чисел в столбик.
На следующем рисунке показано сложение двух двоичных чисел командой ADD:
При сложении происходит перенос из 7-го разряда в 8-й, как раз на границе между байтами. Если мы будем складывать эти числа по частям командой ADD, то перенесённый бит потеряется и в результате мы получим ошибку. К счастью, перенос из старшего разряда всегда сохраняется в флаге CF. Чтобы прибавить этот перенесённый бит, достаточно применить команду ADC:
//Сложение двух чисел с учетом переноса: FFFFFFAA + FFFF
Система команд x86
Влияние команды на флаги и форматы команды:
Вычитание imm8 из регистра AL
Вычитание imm16 из регистра AX
Вычитание imm32 из регистра EAX
Вычитание imm16 из r/m16
Вычитание imm32 из r/m32
Вычитание знакорасширенного imm8 из r/m16
Вычитание знакорасширенного imm8 из r/m32
Вычитание байтового регистра из r/m8
Вычитание 16-битного регистра из r/m16
Вычитание 32-битного регистра из r/m32
Вычитание r/m8 из байтового регистра
Вычитание r/m16 из 16-битного регистра
Вычитание r/m32 из 32-битного регистра
Описание:
Команда SUB (Subtract) относится к группе команд целочисленной (или двоичной) арифметики (Binary Arithmetic Instructions) и производит целочисленное вычитание, вычитая из первого операнда (DEST) второй операнд (SRC) (операнды могут быть знаковыми или беззнаковыми). Первый операнд (операнд-назначение, DEST) может быть переменной в регистре или в памяти (r8, r16, r32, r/m8, r/m16, r/m32). Второй операнд (операнд-источник, SRC) — непосредственным значением (imm8, imm16, imm32), переменной в регистре или в памяти. При этом оба операнда одновременно не могут быть переменными в памяти.
Результат вычитания командой SUB помещается на место первого операнда (DEST). Флаги в регистре EFLAGS устанавливаются в соответствии с полученным результатом.
При вычитании непосредственного значения imm8 или imm16 из двухбайтного или четырехбайтного операнда-источника непосредственная величина прежде всего знакорасширяется до размера первого операнда, и только после этого выполняется вычитание.
Команда SUB позволяет манипулировать целочисленными операндами как в беззнаковом формате, так и в формате со знаком. При вычитании данных со знаком флаг знака EFLAGS.SF будет отражать знак полученного результата. Флаг переполнения EFLAGS.OF установится в 1, если при вычитании целочисленных значений со знаком, представленных в обратном коде или в дополнительном коде, произошло переполнение (заем в старший значащий разряд, которому соответствует бит, предшествующий разряду знака), то есть полученный результат превышает доступный размер операнда-назначения (DEST). По сути, это аналогично тому, как флаг EFLAGS.CF отражает переполнение (заем) при вычитании беззнаковых операндов. Например, при вычитании двух 32-битных значений, представленных в дополнительном коде, это может выглядеть следующим образом:
mov eax, operand1 ; EAX = operand1, первое 32-битное слагаемое помещаем в EAX
sub eax, operand2 ; производим вычитание двух 32-битных операндов в дополнительном коде
into ; переход к обработчику прерывания в случае переполнения
Флаг вспомогательного (или дополнительного) переноса EFLAGS.AF помогает манипулировать данными в двоично-десятичном формате (упакованный BCD-формат). Он устанавливается, если при вычитании возникает заем в младшую тетраду из старшей тетрады младшего байта результата. Используя команду DAS сразу же вслед за командой SUB, можно произвести так называемую десятичную коррекцию результата вычитания и получить разность в таком же упакованном BCD-формате, как и исходные операнды.
Команда SUB с операндом-назначением (DEST), являющимся переменной в памяти, может использоваться совместно с префиксом блокировки LOCK, который обеспечит атомарное исполнение команды.
Операция:
IF (разрядность SRC меньше разрядности DEST)
Особые ситуации защищенного режима:
#GP(0), если операнд-назначение (DEST) находится в памяти в сегменте, запрещенном для записи.
#GP(0), если при обращении к операнду в памяти в сегменте DS, ES, FS или GS используется нулевой селектор.
#GP(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в сегменте CS, DS, ES, FS или GS.
#SS(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в стековом сегменте SS.
Intel386 … :
#PF(Код ошибки) при страничной ошибке.
#UD при использовании префикса LOCK, если первый операнд команды (DEST) не является значением в памяти.
Intel486 … :
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).
Особые ситуации режима реальной адресации:
#GP, если любая часть операнда в памяти находится вне допустимого для реального режима пространства эффективных адресов в сегменте CS, DS, ES, FS или GS.
#SS, если любая часть операнда в памяти выходит за допустимую для реального режима верхнюю границу стекового сегмента SS.
Intel386 … :
#UD при использовании префикса LOCK, если первый операнд команды (DEST) не является значением в памяти.
Особые ситуации режима V86:
#GP(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в сегменте CS, DS, ES, FS или GS.
#SS(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в стековом сегменте SS.
Intel386 … :
#PF(Код ошибки) при страничной ошибке.
#UD при использовании префикса LOCK, если первый операнд команды (DEST) не является значением в памяти.
Intel486 … :
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).
Замечание:
К командам целочисленной арифметики относятся команды ADD, ADC, SUB, SBB, IMUL, MUL, IDIV, DIV, INC, DEC, NEG, CMP.
В свою очередь, сами названные команды целочисленной арифметики делятся на следующие подгруппы:
FasmWorld Программирование на ассемблере FASM для начинающих и не только
Учебный курс. Часть 14. Режимы адресации
Автор: xrnd | Рубрика: Учебный курс | 22-04-2010 |
Распечатать запись
Режимы адресации — это различные способы указания местоположения операндов. До этой части в учебном курсе использовались только простые режимы адресации: операнды чаще всего находились в регистрах или в переменных в памяти. Но в процессоре Intel 8086 существуют также более сложные режимы, которые позволяют организовать работу с массивами, структурами, локальными переменными и указателями. В этой части я расскажу о всех возможных режимах адресации и приведу примеры их использования.
1. Неявная адресация
Местоположение операнда фиксировано и определяется кодом операции. Примеры:
Команда CBW всегда работает с регистрами AX и AL, а у команды MUL фиксировано положение первого множителя и результата. Такой режим адресации делает машинную команду короткой, так как в ней отсутствует указание одного или нескольких операндов.
2. Непосредственная адресация
При непосредственной адресации значение операнда является частью машинной команды. Понятно, что в этом случае операнд представляет собой константу. Примеры:
mov al,5 add bx,1234h mov dx,a
Обратите внимание, что в третьей строке в DX помещается адрес метки или переменной a, а вовсе не значение по этому адресу. Это особенность синтаксиса FASM. По сути адрес метки тоже является числовой константой.
3. Абсолютная прямая адресация
В машинной команде содержится адрес операнда, находящегося в памяти. Пример:
Вот тут уже в DX помещается значение из памяти по адресу a. Сравните с предыдущим пунктом. Квадратные скобки обозначают обращение по адресу, указанному внутри этих скобок.
4. Относительная прямая адресация
Этот режим используется в командах передачи управления. В машинной команде содержится смещение, которое прибавляется к значению указателя команд IP. То есть указывается не сам адрес перехода, а на сколько байтов вперёд или назад надо перейти. Пример:
У такого режима адресации два преимущества. Во-первых, машинная команда становится короче, так она содержит не полный адрес, а только смещение. Во-вторых, такой код не зависит от адреса, по которому он размещается в памяти.
5. Регистровая адресация
Операнд находится в регистре. Пример:
6. Косвенная регистровая (базовая) адресация
Адрес операнда находится в одном из регистров BX, SI или DI. Примеры:
Размер операнда в памяти здесь определяется размером первого операнда. Так как AX — 16-разрядный регистр, то из памяти берётся слово по адресу в BX. Так как DL — 8-разрядный регистр, то из памяти берётся байт по адресу в SI. Это правило верно и для других режимов адресации.
7. Косвенная регистровая (базовая) адресация со смещением
Адрес операнда вычисляется как сумма содержимого регистра BX, BP, SI или DI и 8- или 16-разрядного смещения. Примеры:
add ax,[bx+2] mov dx,[array1+si]
В качестве смещения можно указать число или адрес метки. О размере смещения не беспокойтесь — компилятор сам его определяет и использует нужный формат машинной команды.
8. Косвенная базовая индексная адресация
Адрес операнда вычисляется как сумма содержимого одного из базовых регистров BX или BP и одного из индексных регистров SI или DI. Примеры:
mov ax,[bp+si] add ax,[bx+di]
Например, в одном из регистров может находиться адрес начала массива в памяти, а в другом — смещение какого-то элемента относительно начала. А вообще, всё зависит от вашей фантазии 🙂
9. Косвенная базовая индексная адресация со смещением
Адрес операнда вычисляется как сумма содержимого одного из базовых регистров BX или BP, одного из индексных регистров SI или DI и 8- или 16-разрядного смещения. Примеры:
mov al,[bp+di+5] mov bl,[array2+bx+si]
Пример программы
Допустим, имеется массив 32-битных целых чисел со знаком. Количество элементов массива хранится в 16-битной переменной без знака. Требуется вычислить среднее арифметическое элементов массива и сохранить его в 32-битной переменной со знаком. Я намеренно использовал разные режимы адресации, хотя тоже самое можно написать проще.
Упражнение
Объявите в программе два массива 16-битных целых со знаком. Количество элементов массивов должно быть одинаковым и храниться в 8-битной переменной без знака. Требуется из последнего элемента второго массива вычесть первый элемент первого, из предпоследнего — вычесть второй элемент и т.д. Результаты можете выкладывать в комментариях.
Команды сложения и вычитания
Лабораторная работа №2
«Изучение команд сложения и вычитания»
Цель работы: изучить форматы и правила работы с командами сложения и вычитания микропроцессора i8086.
Краткие теоретические сведения.
1. Форматы арифметических данных
2. Команды сложения
3. Команды вычитания
4. Команда обращения знака
5. Команды расширения знака
Коррекция результата сложения для представления в кодах ASCII и в упакованном десятичном формате (команды AAA и DAA).
Как уже упоминалось, при выполнении сложения микропроцессор 8×86 рассматривает операнды как двоичные числа. Что же произойдет, если они будут двоично-десятичными кодами чисел (кратко десятичными или BCD-числа¬ми)? Разберемся в этом на примере. При сложении упакованных BCD-чисел 26 и 55 микропроцессор 8×86 выполнит следующее двоичное сложение:
ADD AL,BL ;Сложить неупакованные числа, находящиеся в AL и BL
ААА ; и преобразовать результат в неупакованное число
Если результат превышает 9, то команда ААА добавляет 1 к содержимому регист¬ра АН (чтобы учесть избыточную цифру) и полагает флаг CF равным 1; в против¬ном случае она обнуляет флаг CF. Кроме того, команда ААА изменяет состояние флага AF и оставляет значения флагов PF, ZF, SF и OF неопределенными. Но так как в данном случае только флаг CF имеет смысл, то считайте значения остальных флагов уничтоженными.
Команда DAA преобразует содержимое регистра AL в две правильные упако¬ванные десятичные цифры. Она используется в следующем контексте:
ADD AL,BL ;Сложить упакованные BCD-числа в AL и BL
DAA ; и преобразовать результат в упакованное число
Если результат превышает предельное значение для упакованных BCD-чисел (99), то команда DAA добавляет 1 к содержимому регистра АН и полагает флаг CF равным 1. Кроме того, команда DAA изменяет состояния флагов PF, AF, ZF и CF и оставляет значение флага OF неопределенным. Но так как в данном случае только флаг CF имеет смысл, то считайте остальные пять флагов уничтоженными.
Как ни странно, приращение значения 8-битового регистра отнимает у микро¬процессора 8×86 больше времени, чем приращение значения 16-битового регистра. Это вызвано тем, что разра¬ботчики фирмы Intel предполагали, что программисты будут чаще пользоваться счетчиками размером в слово, а не байт, и предусмотрели специальную однобай¬товую версию команды INC для 16-битовых регистров.
0000 1010 (10)
+1111 1001 (-7)
0000 0011 (Ответ: 3)
Эврика! Мы получили правильный ответ!
Так как микропроцессор 8×86 выполняет дополнение до двух автоматически, то Вам эта операция понадобится в редких случаях. Позже в этом разделе мы рассмотрим команду NEG, посредством которой можно выполнить дополнение до двух, если оно когда-либо Вам понадобится.
приемник = приемник — источник
DEC CX ;Уменьшить знамение 16-битового
DEC AL ; или 8-битового регистра
DEC MEM_BYTE ;Уменьшить значение байта
DEC MEM_WORD[BX] ;или слова памяти
Команда обращения знака NEG.
Команда NEG вычитает значение операнда-приемника из нулевого значения и тем самым формирует его дополнение до двух. Команда NEG оказыва¬ет на флаг то же действие, что и команда SUB. Но поскольку один из операндов равен 0, то можно точнее описать условия изменения состояний флагов. Итак, при исполнении команды NEG флаги изменяются следующим образом:
Флаг переноса CF и флаг знака SF равны 1, если операнд представляет собой ненулевое положительное число; в противном случае они равны 0.
Флаг четности PF равен 1, если результат имеет четное число битов, равных 1; в противном случае он равен 0.
Флаг нуля ZF равен 1, если операнд равен 0; в противном случае он равен 0.
Флаг переполнения OF равен 1, если операнд-байт имеет значение 80Н или операнд-слово имеет значение 8000Н; в противном случае он равен 0.
Команда NEG полезна для вычитания значения регистра или ячейки памяти из непосредственного значения. Например, Вам нужно вычесть значение регистра AL из 100. Так как непосредственное значение не может служить приемником, то команда SUB 100, AL недопустима. В качестве альтернативы можно обратить знак содержимого регистра AL и добавить к нему 100:
Команда расширения знака.
Существуют две команды, позволяющие выполнять операции над смешанными данными за счет удвоения размера операнда со знаком. Команда CBW (convert byte to word — преобразовать байт в слово) воспроизводит 7-й бит регистра AL во всех битах регистра AH.
Команда CWD (convert word to double word — преобразовать слово в двойное слово) воспроизводит 15-й бит регистра AX во всех битах регистра DX.
Таким образом, команда CBW позволяет сложить байт и слово, вычесть слово из байта и т. д. Аналогично, команда CWD позволяет разделить слово на слово.
Приведем несколько примеров:
CBW ;Сложить байт в AL со словом в BX
ADD AX,BX
CBW ;Умножить байт в AL на слово в BX
IMUL BX
CWD ;Разделить слово в AX на слово в BX
IDIV BX
Индивидуальное задание.
Вычислить следующее выражение:
F = КОН1 оп1 (КОН2 оп2 Х оп3 Y) оп4 Z оп5 КОН3
где
КОН1, КОН2, КОН3 – числовые константы, согласно табл. 1
оп1, оп2, оп3, оп4, оп5 – операции сложения и вычитания согласно табл. 2
X, Y – переменные
Числовые константы из табл. 1 берутся согласно первой цифре варианта, операции сложения и вычитания из табл. 2 – согласно второй цифре варианта.
Исходные данные хранятся в памяти с адреса 0900H, вычисление выражения производится на Ассемблере, выводимые результаты — располагаются в памяти с адреса 1000Н.
КОН1
4589
КОН2
29
КОН3
562235
оп1
—
оп2
—
оп3
+
оп4
+
оп5
+
Пример. У студента индивидуальный вариант 9. Строим индивидуальное выражение для вычисления: F=458 – (481 + X + Y) + Z — 36
Ассемблер. Арифметические инструкции
Обновл. 16 Сен 2021 |
На этом уроке мы будем разбираться с арифметическими инструкциями в ассемблере на примере 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
Есть 2 инструкции для умножения двоичных данных:
инструкция MUL (от англ. «MULTIPLY») обрабатывает данные unsigned;
инструкция IMUL (от англ. «INTEGER MULTIPLY») обрабатывает данные signed.
Обе инструкции влияют на флаги переноса и переполнения.
Синтаксис инструкций MUL/IMUL:
Множимое в обоих случаях будет находиться в аккумуляторе, в зависимости от размера множимого и множителя, и результат умножения также сохраняется в двух регистрах, в зависимости от размера операндов.
Рассмотрим 3 разных сценария:
Сценарий №1: Перемножаются 2 значения типа byte. Множимое находится в регистре AL, а множителем является значение типа byte в памяти или в другом регистре. Результат произведения находится в AX. Старшие 8 бит произведения хранятся в AH, а младшие 8 бит хранятся в AL:
Сценарий №3: Перемножаются 2 значения типа doubleword. Множимое должно находиться в EAX, а множителем является значение типа doubleword, хранящееся в памяти или в другом регистре. Результат умножения сохраняется в регистрах EDX и EAX. Биты старшего порядка сохраняются в регистре EDX, а биты младшего порядка сохраняются в регистре EAX:


Распечатать запись
