возможна ли такая операция sub ax dl
Система команд 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 для начинающих и не только
Учебный курс. Часть 9. Сложение и вычитание
Автор: xrnd | Рубрика: Учебный курс | 28-03-2010 |
Распечатать запись
Теперь мы уже знаем, как представляются числа в компьютере, и можем перейти к изучению команд процессора. Начнём с самых простых арифметических операций: сложения и вычитания.
Сложение
Для сложения двух чисел предназначена команда ADD. Она работает как с числами со знаком, так и с числами без знака (это особенность дополнительного кода).
Операнды должны иметь одинаковый размер (нельзя складывать 16- и 8-битное значение). Результат помещается на место первого операнда. В общем, эти правила справедливы для большинства команд.
После выполнения команды изменяются флаги, по которым можно определить характеристики результата:
add ax,5 ;AX = AX + 5 add dx,cx ;DX = DX + CX add dx,cl ;Ошибка: разный размер операндов.
Вычитание
Вычитание выполняется с помощью команды SUB. Результат также помещается на место первого операнда и опять же выставляются флаги. Единственная разница в том, что происходит вычитание, а не сложение.
На самом деле вычитание в процессоре реализовано с помощью сложения. Процессор меняет знак второго операнда на противоположный, а затем складывает два числа. Если вам необходимо в программе поменять знак числа на противоположный, можно использовать команду NEG. У этой команды всего один операнд.
Инкремент и декремент
Очень часто в программах используется операция прибавления или вычитания единицы. Прибавление единицы называется инкрементом, а вычитание — декрементом. Для этих операций существуют специальные команды процессора: INC и DEC. Обратите внимание, что эти команды не изменяют значение флага CF.
Пример программы
Чтобы всё стало совсем понятно, напишем небольшую программу. Требуется вычислить значение формулы: e=a-(b+c-1)+(-d). Все числа являются 8-битными целыми со знаком. Объявим их после кода и придумаем какие-нибудь значения. Вот что у меня получилось:
Квадратные скобки означают, что операнд находится по адресу, указанному внутри этих скобок. Так как вместо имени переменной FASM подставляет её адрес, то такая запись позволяет прочитать или записать значение переменной.
Запустив программу в Turbo Debugger, можно посмотреть её выполнение по шагам. Значения переменных можно увидеть в окне дампа памяти. Для этого нужно кликнуть правой кнопкой в этом окне и выбрать в меню пункт Goto…. Переменные начинаются в памяти с адреса 011Fh (этот адрес в первой команде).
В этих байтах легко угадываются наши переменные:
Упражнение
Напишите программу для вычисления формулы k=m+1-(n-1-r). Все числа 16-битные целые со знаком. Запустите в отладчике и проверьте правильность вычисления. Результаты можете выкладывать в комментариях 🙂
Возможна ли такая операция 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
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-битной переменной без знака. Требуется из последнего элемента второго массива вычесть первый элемент первого, из предпоследнего — вычесть второй элемент и т.д. Результаты можете выкладывать в комментариях.
Возможна ли такая операция sub ax dl
На этом шаге мы познакомимся с основными арифметическими командами.
Перечислим основные арифметические команды, используемые для организации вычислений.
Рассмотрим более подробно перечисленные команды.
Пример. Пусть регистр DL содержит число 58H, однобайтовая ячейка памяти TEST_BYTE содержит 27H. После выполнения команды ADD TEST_BYTE,DL в ячейку памяти будет записано 7FH:
Пример 2. Проиллюстрируем использование этой команды при сложении так называемых «длинных» чисел, которые на помещаются в одно слово. Пусть требуется сложить два таких числа:
Сначала сложим младшие слова этих чисел, используя команду ADD :
Первый операнд может быть задан в регистре или ячейке памяти. Второй операнд может быть задан в регистре, ячейке памяти или непосредственно константой. Не допускается использование сегментных регистров или одновременная запись этих операндов в ячейках памяти. Операнды могут быть как знаковыми, так и беззнаковыми числами. Возможно выполнение 8- и 16-разрядных операций.
5. SBB (Вычитание с заемом). Определяет разность двух операндов, и, кроме того, из уменьшаемого вычитается содержимое флага переноса :
Результат помещается на место первого операнда, предыдущее значение которого теряется. Содержимое второго операнда не изменяется.
Первый операнд может быть задан в регистре или ячейке памяти. Второй операнд, кроме того, может быть задан константой. Не допускается использовать для записи операндов сегментные регистры или задавать оба операнда в ячейках памяти. Операнды могут быть однобайтовыми или двухбайтовыми числами со знаком или без знака. Возможность заема позволяет использовать команду SBB для организации вычитания чисел с разрядностью, превышающей 16 бит.
6. DEC (Декремент). Уменьшает содержимое операнда на единицу :
Если содержимое регистра AH после однобайтового умножения или содержимое регистра DX после двухбайтового умножения не равны нулю, флаги CF и OF устанавливаются в 1. В противном случае они сбрасываются в 0. Состояние флагов SF, ZF, AF, PF после команды MUL не определено.
Результат выполнения команды деления приведен в таблице 3.
Операнд может быть задан в регистре общего назначения или ячейке памяти, при этом операнд рассматривается как беззнаковый 8- или 16-битовый делитель соответственно при однобайтовом и двухбайтовом делении.
После выполнения команды DIV состояния разрядов регистра флагов процессора не определены. Если произошло переполнение, то частное и остаток не определены.
11. Для написания простейших программ на языке Ассемблера необходима еще одна команда, непосредственно не относящаяся с арифметическим командам. Это команда MOV (Пересылка данных) :
Второй операнд при выполнении команды MOV занимает место хранения первого операнда. При этом первый операнд теряется.
Первый операнд может быть задан в регистре общего назначения, регистре сегмента (кроме регистра CS ) или ячейки памяти. Второй операнд, кроме того, может быть еще и константой. Команда MOV работает как с однобайтовыми, так и с двухбайтовыми словами.
Пример. Пусть регистр AX содержит слово 0001H. После выполнения команды NEG AX содержимым регистра AX будет FFFFH. Таким образом, команда NEG инвертирует значения битов и прибавляет 1.