Иллюстрированный самоучитель по Assembler. Команды арифметического вычитания SUB и SBB

ADC op1, ор2 - сложение с переносом.

(ор1) ← (ор1) + (ор2) + С

Прибавляет к первому операнду второй операнд и содержимое флага переноса С. Старое значение первого операнда при этом уничтожается, второй операнд остается неизменным.

Первый операнд может быть регистром общего назначения* или ячейкой памяти. Второй операнд может быть регистром, ячейкой памяти или явно заданным числом. Знак этого числа расширяется, чтобы второй операнд стал того же размера, что и первый.

Нельзя, чтобы оба операида были ячейками памяти. Инструкции ADC безразлично, какие числа - со знаком или без - складываются. На всякий случай процессор устанавливает флаги для обоих типов сложения (С - для сложения чисел без знака, O - для чисел со знаком).

Основное назначение инструкции adc - сложение "длинных" чисел, не умещающихся в 32 битах.

Меняет флаги OSZAPC.

*То есть одним из восьми регистров (E)AX, (E)BX, (E)CX. (E)DX, (EB)P, (E)SP, (E)SI, (E)DI или их частью, например AL, BH и т. д.

ADC Целочисленное сложение с переносом

Команда adc осуществляет сложение первого и второго операндов, прибаатяя к результату значение флага переноса CF. Исходное значение первого операнда (приемника) теряется, замещаясь результатом сложения. Второй операнд не изменяется. В качестве первого операнда команды adc можно указывать регистр (кроме сегментного) или ячейку памяти, в качестве второго - регистр (кроме сегментного), ячейку памяти или непосредственное значение, однако не допускается определять оба операнда одновременно как ячейки памяти. Операнды могут быть байтами или словами и представлять числа со знаком или без знака. Команда adc (совместно с командой add) обычно используется для сложения 32-разрядных чисел. Команда воздействует на флаги OF, SF, ZF, AF, PF и CF.

Пример 1

Mov AX,1125h adc AX,2C25h ;AX=3D4Bh, если CF был = 1 ;AX=3D4Ah, если CF был = 0
Пример 2 ; В полях данных: numlow dw 0FFFFh ;Младшая часть 2-го слагаемого numhigh dw 000Sh ;Старшая часть 2-го слагаемого;Число 0005FFFFh=393215 ;В программном сегменте: mov AX,000Sh ;Младшая часть 1-го слагаемого mov BX,0002h ;Старшая часть 1-го слагаемого;Число 00020005h=131077 add АХ,numlow ;Сложение младших частей. АХ=4, CF=1 adc BX, numhigh ;Сложение старших частей с;переносом.ВХ:АХ=0008:0004h. ;Число 00080004h=524292
Допустимо использование 32-битовых операндов и дополнительных режимов адресации 32-разрядных процессоров. Команда adc с 32-разрядными операндами может использоваться для сложения 64-разрядных целых чисел. Пример 3 ; В полях данных mem321 dd 0FFFFFFFFh ;Младшая часть 1-го слагаемого mem32h dd 98765432h ;Старшая часть 1-го слагаемого; В программном сегменте mov EAX,1 ;Младшая часть 2-го слагаемого mov EBX,0 ;Старшая часть 2-го слагаемого add EAX,mem321 ;Складываем младшие половины;Сумма=100000000Ь>32 бит;EAX=000000h, перенос adc EBX,mem32h ;Складываем старшие половины;и перенос. EBX=90000001h ;Сумма: 9876543300000000h
ADD Целочисленное сложение

Команда add осуществляет сложение первого и второго операндов. Исходное значение первого операнда (приемника) теряется, замещаясь результатом сложения. Второй операнд не изменяется. В качестве первого операнда команды add можно указывать регистр (кроме сегментного) или ячейку памяти, в качестве второго - регистр (кроме сегментного), ячей-ку памяти или непосредственное значение, однако не допускается опре-делять оба операнда одновременно как ячейки памяти. Операнды могут быть байтами или словами и представлять числа со знаком или без знака. Команду add можно использовать для сложения как обычных целых чи-сел, так и двоично-десятичных (с использованием регистра АХ для хра-нения результата). Если складываются неупакованные двоично- десятич-ные (BCD) числа, после команды add следует использовать команду ааа; если складываются упакованные числа, то команду daa. Команда воздействует на флаги OF, SF, ZF, AF, PF и CF. Пример 1

Mov BX,lFFEh mov CX,3 add BX,CX ;BX=2001h, CX=0003h
Пример 2 mov AX,25h add AX,12h ;AX=0037h
Пример 3 ; В полях данных: mem dw 128 ;B программном сегменте: add mem,100 ;mem=228
Пример 4 mov AX,0507h ;BCD распакованное 57 add AL,05h ;BCD 5, AX=050Ch aaa ;AX=0602h, BCD 62
Пример 5 mov AL,57h ;BCD упакованное 57 add AL,05h ;BCD 5, AL=5Ch daa ;AL=62h, BCD 62

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

Mov EAX,98765432h add EAX,11111111h ; EAX=A9876543h
AND Логическое И

Команда and осуществляет логическое (побитовое) умножение первого операнда на второй. Исходное значение первого операнда (приемника) теряется, замещаясь результатом умножения. В качестве первого операнда команды and можно указывать регистр (кроме сегментного) или ячейку памяти, в качестве второго - регистр (кроме сегментного), ячейку памяти или непосредственное значение, однако не допускается определять оба операнда одновременно как ячейки памяти. Операнды могут быть байтами или словами. Команда воздействует на флаги SF, ZF и PF. Правила побитового умножения:

Первый операнд-бит 0101 Второй операнд-бит 0011 Бит результата 0001 Пример 1 mov AX,0FFEh and AX,5555h ;AX=0554h Пример 2 ; В полях данных: mem dw 0С003h ;В программном сегменте: mov AX,700Eh and AX,mem ;AX=4002h

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

Mov EDX, 0FA8 8 0 0 4 lh and EDX,0FF00000Fh ; EDX = FA000001h
386P+ ARPL
Коррекция запрашиваемого уровня привилегий селектора

Команда aprl сравнивает селектор с образцом, содержащим максимально допустимый уровень привилегий (обычно используется селектор CS) и устанавливает проверяемое значение в соответствии с меньшим из двух уровней привилегий. Если изменение уровня не потребовалось, флаг ZF сбрасывается, если потребовалось - устанавливается. В качестве первого операнда команды aprl может использоваться 16-разрядный регистр или слово памяти с проверяемым селектором; в качестве второго операнда - 16-разрядный регистр с селектором-образцом. 386+ BOUND
Проверка индекса массива на выход за границы массива

Команда bound проверяет, лежит ли указанный индекс, рассматриваемый, как число со знаком, внутри заданных вторым операндом границ. Если индекс выходит за границы массива снизу или сверху, генерируется прерывание с вектором 5. Первый операнд должен быть регистром, содержащим проверяемый индекс, второй - адресом поля памяти с двумя границами проверяемого массива. В команде bound допустимо использование как 16-битовых, так и 32-битовых операндов (но и первый, и второй операнды должны быть одного типа).

ADC Целочисленное сложение с переносом

Команда adc осуществляет сложение первого и второго операндов, прибавляя к результату значение флага переноса CF. Исходное значение первого операнда (приемника) теряется, замещаясь результатом сложения. Второй операнд не изменяется. В качестве первого операнда команды adc

Операнды могут быть байтами или словами и представлять числа со знаком или без знака. Команда adc (совместно с командой add ) обычно используется для сложения 32-разрядных чисел. Команда воздействует на флаги OF, SF, ZF, AF, PF и CF.

Пример 1 :

Mov AX,1125h adc AX,2C25h; AX=3D4Bh, если CF был = 1 ;AX=3D4Ah, если CF был = 0

Пример 2 :

; В полях данных: numlow dw 0FFFFh; Младшая часть 2-го слагаемого numhigh dw 000Sh; Старшая часть 2-го слагаемого;Число 0005FFFFh=393215 ;В программном сегменте: mov AX,000Sh; Младшая часть 1-го слагаемого mov BX,0002h; Старшая часть 1-го слагаемого;Число 00020005h=131077 add АХ,numlow; Сложение младших частей. АХ=4, CF=1 adc BX, numhigh; Сложение старших частей с переносом. ВХ:АХ=0008:0004h. ;Число 00080004h=524292

Допустимо использование 32-битовых операндов и дополнительных режимов адресации 32-разрядных процессоров. Команда adc с 32-разрядными операндами может использоваться для сложения 64-разрядных целых чисел.

Пример :

; В полях данных mem321 dd 0FFFFFFFFh; Младшая часть 1-го слагаемого mem32h dd 98765432h; Старшая часть 1-го слагаемого; В программном сегменте mov EAX,1; Младшая часть 2-го слагаемого mov EBX,0; Старшая часть 2-го слагаемого add EAX,mem321; Складываем младшие половины;Сумма=100000000h>32 бит;EAX=000000h, перенос adc EBX,mem32h; Складываем старшие половины и перенос. EBX=90000001h; Сумма: 9876543300000000h

ADD Целочисленное сложение

Команда add осуществляет сложение первого и второго операндов. Исходное значение первого операнда (приемника) теряется, замещаясь результатом сложения. Второй операнд не изменяется. В качестве первого операнда команды add можно указывать регистр (кроме сегментного) или ячейку памяти, в качестве второго - регистр (кроме сегментного), ячейку памяти или непосредственное значение, однако не допускается определять оба операнда одновременно как ячейки памяти.

Операнды могут быть байтами или словами и представлять числа со знаком или без знака. Команду add можно использовать для сложения как обычных целых чи-сел, так и двоично-десятичных (с использованием регистра АХ для хра-нения результата). Если складываются неупакованные двоично-десятичные (BCD) числа, после команды add следует использовать команду ааа; если складываются упакованные числа, то команду daa . Команда воздействует на флаги OF, SF, ZF, AF, PF и CF.

Пример 1 :

Mov BX,lFFEh mov CX,3 add BX,CX; BX=2001h, CX=0003h

Пример 2 :

Mov AX,25h add AX,12h; AX=0037h

Пример 3 :

; В полях данных: mem dw 128 ;B программном сегменте: add mem,100; mem=228

Команды сложения - ADD, ADC

Команды ADD (add - сложить) и ADC (add with carry- сложить с переносом) могут складывать как 8-, так и 16-битовые операнды.

Команда ADD складывает содержимое операнда-источника и операнда-приемника и помещает результат в операнд-приемник.

Формат команды: ADD приемник, источник

В символической нотации ее действия можно описать следующим образом: приемник:= приемник + источник (в приемник записывается сумма содержимого приемника и источника).

Команда ADC делает то же, что и команда ADD, но складывает не два, а три слагаемых: приемник, источник и флаг переноса.

Формат команды: ADC приемник, источник + CF

В символической нотации ее действия можно описать как:

приемник:= приемник + источник + содержимое флага переноса.

Перенос при сложении двоичных чисел аналогичен переносу при сложении десятичных чисел в столбик. Когда ЭВМ складывает двоичные числа и сумма не помещается в операнде-приемнике, то генерируется перенос. Как известно, 8-битовый регистр может содержать значения без знака в диапазоне от 0 до 255. Если мы, например, выполним двоичное сложение чисел 250 и 10, то получим следующий результат:

1111 1010; двоичное представление числа 250.

0000 1010 ; двоичное представление числа 10.

1 0000 0100; двоичное представление суммы, равной 260.

Результат верен, но занимает 9 двоичных битов. Если использовались 8 - битовые регистры, то младшие 8 битов будут занесены в регистр-приемник, а девятый бит- во флаг переноса CF.

Теперь понятно, почему микропроцессор 8086 имеет две разные команды сложения. Одна из них (ADD) может складывать значения, представляемые байтами или словами, а также младшие части значений повышенной точности. Другая команда (ADC) используется для сложения старших частей значений повышенной точности.

Складываемые операнды могут находиться в памяти, регистре или иметь непосредственное значение. Например:

ADD АХ,MEM_WORD; прибавить содержимое ячейки памяти к регистру,

ADD MEM_WORD,AX; или наоборот, прибавить содержимое регистра к ячейки памяти.

ADD AL, 10; прибавить константу к содержимому регистра.

ADD MEM_BYTE,8H; сложить константу и содержимое ячейки памяти.

Допускается большинство возможных комбинаций, но нельзя складывать содержимое двух ячеек памяти или использовать в качестве приемника непосредственное значение (число).

Команды ADD и ADC могут воздействовать на следующие шесть флагов:

флаг переноса CF равен 1, если результат сложения не помещается в операн­де-приемнике, в противном случае он равен 0;

флаг четности PF равен 1, если результат имеет четное число битов со значением 1, в противном случае он равен 0;

AF равен 1, если результат сложения десятичных чисел требует коррекции;

флаг нуля ZF равен 1, если результат равен 0;

флаг знака SF равен 1, если результат отрицателен (старший бит равен 1), в противном случае он равен 0;

флаг переполнения OF равен 1, если слагаемое двух чисел одного знака превышает диапазон допустимых значений приемника в обратном коде, а сам приемник при этом меняет знак. Иначе флаг OF равен 0.

Команда увеличения значения приемника на единицу – INC

Команда INC (increment - прирастить) добавляет 1 к содержимому регистра или ячейки памяти, но в отличие от команды ADD не воздействует на флаг переноса CF. Формат команды: INC приемник .

Команда INC удобна для увеличения значений счетчиков в циклах команд. Ее можно использовать и для увеличения значения индексного регистра при доступе к последовательно расположенным ячейкам памяти. Операнд интерпретируется как число без знака.

Например:

INC CX; увеличить значение 16-битового

INC AL; или 8-битового регистра на единицу.

INC MEM_BYTE; увеличить значение байта

INC MEM_WORD; или слова памяти на единицу.

Не допускается использовать в качестве операнда непосредственное значение.

Команды вычитания - SUB, и вычитания с заемом SBB

Команды SUB (substract - вычесть) и SBB (substract with borrow - вычесть с заемом) аналогичны соответственно командам сложения ADD и ADC, только при вычитании флаг переноса CF действует как признак заема. Формат команды: SUB приемник,источник;

Команда SUB вычитает операнд -источник из операнда -приемника и помещает результат в приемник, в символической нотации:

приемник:= приемник – источник.

Команда SBB делает то же самое, но дополнительно вычитает из приемника значение флага переноса CF:

SUB приемник,источник – СF;

Приемник:= приемник - источник - содержимое флага переноса.

Как и в случае сложения, команды SUB и SBB выполняют две отдельные функции. Первая команда вычитает числа размером в байт или слово, а также младшие биты чисел повышенной точности (младшая часть числа расположена в регистре АХ, а старшая часть в регистре DX). Вторая команда вычитает старшие биты чисел повышенной точности. Например, команда SUB AX,CX; вычитает содержимое регистра СХ из содержимого регистра АХ и возвращает результат в регистр АХ.

Если размеры операндов превышают 16 бит, то необходимо применить следующую последовательность команд:

SUB АХ,CX; Вычесть младшие 16 бит;

SBB BX,DX; а затем старшие 16 бит.

Здесь мы вычитаем из 32-битового числа, помещенного в регистры АХ и ВХ, 32-битовое число, находящееся в регистрах СХ и DX. При вычитании содержимого регистра DX из содержимого регистра ВХ команда SBB учитывает возможность заема при выполнении первого вычитания.

SUB АХ, MEM; Вычесть из регистра содержимое ячейки памяти.

SUB MEM ,AX; Вычесть из ячейки памяти регистр.

SUB AL,1O; Вычесть константу из регистра.

SUB MEM_BYTE,OFh; Вычесть константу из ячейки памяти.

Нельзя непосредственно вычесть содержимое одной ячейки памяти из другой или использовать непосредственное значение как приемник.

Команды SUB и SBB могут воздействовать на шесть флагов следующим образом:

· устанавливают флаг переноса CF в 1, если требуется заем, в противном случае он равен 0;

· устанавливают флаг четности PF в 1, если результат вычитания имеет четное число битов со значением 1, в противном случае он равен 0;

· устанавливают вспомогательный флаг переноса AF в 1, если результат вычитания десятичных чисел требует коррекции, в противном случае он равен 0;

· устанавливают флаг нуля ZF в 1, если результат равен 0, в противном случае он равен 0;

· устанавливают флаг знака SF в 1, если результат отрицателен (старший бит равен 1), в противном случае флаг равен 0;

· устанавливают флаг переполнения OF в 1, если при вычитании результат превышает диапазон значений приемника в обратном коде, а сам приемник изменяет знак.

Флаги SF и OF имеют смысл только при вычитании чисел со знаком, а флаг AF- только при вычитании десятичных чисел.

Команда уменьшения содержимого приемника - DEC

КомандаDEC приемник (decrement-уменьшить) вычитает 1 из содержимого регистра или ячейки памяти, но при этом (в отличие от команды SUB) не воздействует на флаг переноса CF.

Команда DEC часто используется в циклах для уменьшения значения счетчика до тех пор, пока оно не станет нулевым или отрицательным. Ее можно использовать также для уменьшения значения индексного регистра или указателя при доступе к последовательно расположенным ячейкам памяти. Например:

DEC CX; Уменьшить значение 16-битового,

DEC AL; или 8-битового регистра.

DEC MEM_BYTE; Уменьшить значение байтовой,

DEC MEM_WORD; или словной ячейки памяти.

Команды деления - DIV, IDIV

КомандаDIV (divide - разделить) выполняет деление чисел без знака, а команда IDIV (integer divide - разделить целые числа) выполняет деление чисел со знаком. Эти команды имеют формат:

DIV источник ; где источник - делитель размером в байт или слово,

IDIV источник ;находящийся в регистре общего назначения или в ячейке памяти.

Обратите внимание на следующее:

1. Делимое по отношению к делителю должно иметь двойной размер.

2. Делимое всегда должно находиться в регистре АХ (при делении на 8-битовое число) или в регистрах DX и АХ (при делении на 16-битовое число).

3. Результаты команды возвращаются следующим образом:

· если операнд-источник представляет собой байт, то частное возвращается в регистр AL, а остаток в регистр АН;

· если операнд-источник представляет собой слово, то частное возвращается в регистр АХ, а остаток - в регистр DX.

Обе команды оставляют состояние флагов неопределенными, но если частное не помещается в регистре-приемнике (AL или АХ), то микропроцессор генерирует прерывание типа 0 (деление на 0).

4. Переполнение результата деления возникает при следующих условиях:

· делитель равен 0;

· при делении байтов без знака делимое, по меньшей мере, в 256 раз превышает делитель;

· при делении слов без знака делимое, по меньшей мере, в 65 536 раз превышает делитель;

· при делении байтов со знаком частное лежит вне диапазона -128 до +127;

· при делении слов со знаком частное лежит вне диапазона от

32768 до 32767.

Приведем несколько типичных примеров операций деления:

DIV BX; Разделить DX:AX на ВХ, без знака.

DIV MEM_BYTE; Разделить АХ на байт памяти, без знака.

IDIV DL; Разделить АХ на DL со знаком.

IDIV MEM WORD; Разделить DX:AX на слово памяти, со знаком.

Команды DIV и IDIV не позволяют прямо разделить на непосредственное значе­ние, так как процессор не может определить тип данных делителя.

Команды умножения - MUL, IMUL

Команда MUL (multiply-умножить) умножает числа без знака, a IMUL (integer multiply-умно­жить) умножает целые числа со знаком. Множимое и множитель у обеих команд должны быть данные одного типа, то есть байты, слова, двойные слова и т. д.

Эти команды имеют следующий формат:

MUL источник ; гдеисточник - регистр общего назначения,

IMUL источник ; или ячейка памяти размером в байт или слово.

В качестве первого операнда (множимого) команды MUL и IMUL используют содер­жимое регистра AL (при операциях над байтами) или регистра АХ (при операциях над словами). Произведение имеет двойной размер и возвращается следующим образом:

· умножение байтов -возвращает 16-битовое произведение в регистры АН (старший байт) и AL (младший байт);

· умножение слов -возвращает 32- битовое произведение в регистры DX (старшее слово) и АХ (младшее слово). Таким образом, размер произведения n - битных сомножителей равен 2n.

Команда ADC (Add with Carry) относится к группе команд целочисленной (или двоичной ) арифметики (Binary Arithmetic Instructions ) и производит целочисленное сложение двух знаковых или беззнаковых операндов (DEST и SRC ) и флага переноса EFLAGS.CF . Первый операнд (операнд-назначение , DEST ) может быть переменной в регистре или в памяти ( , r16 , r32 , r/m8 , r/m16 , r/m32 ). Второй операнд (операнд-источник , SRC ) — непосредственным значением (imm8 , imm16 , imm32 ), переменной в регистре или в памяти. При этом оба операнда одновременно не могут быть переменными в памяти.

Результат сложения командой ADC помещается на место первого операнда (DEST ). Флаги в регистре EFLAGS устанавливаются в соответствии с полученным результатом.

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

Команда ADC обычно используется в многобайтных или многословных (multi-word ) операциях сложения. В таком случае она идет вслед за командой ADD , которая возвращает сумму младших разрядов многобайтных (многословных) операндов, позволяя при сложении старших разрядов учитывать перенос. Например:

mov edx, 0 ; EDX = 0
mov eax, 0FFFFFFFFh ; первое 32-битное слагаемое помещаем в EAX
add eax, 0FFFFFFFFh ; второе 32-битное слагаемое - 0xFFFFFFFFh, производим сложение двух 32-битных операндов
adc edx, 0 ; EDX = EDX + CF, учитываем перенос
; EDX:EAX = 0000000lh:FFFFFFFEh - полученный 64-битный результат

Команда ADC позволяет манипулировать целочисленными операндами как в беззнаковом формате , так и в формате со знаком . При сложении данных со знаком флаг знака EFLAGS.SF будет отражать знак полученного результата. Флаг переполнения EFLAGS.OF установится в 1, если при сложении целочисленных значений со знаком , представленных в обратном коде или в дополнительном коде , произошло переполнение (перенос из старшего значащего разряда, которому соответствует бит, предшествующий разряду знака), то есть полученный результат превышает доступный размер операнда-назначения (DEST ). По сути, это аналогично тому, как флаг EFLAGS.CF отражает переполнение (перенос) при сложении беззнаковых операндов . Например, при сложении двух 32-битных значений, представленных в обратном коде , это может выглядеть следующим образом:

mov eax, operand1 ; EAX = operand1, первое 32-битное слагаемое помещаем в EAX
add eax, operand2 ; производим сложение двух 32-битных операндов в обратном коде
into ; переход к обработчику прерывания в случае переполнения

adc eax, 0 ; EAX = EAX + CF, учитываем перенос (необходимо для сложения в обратном коде)
; EAX = operand1 + operand2 - результат сложения в обратном коде
jns m1 ; переход, если результат положительный
xor eax, 7FFFFFFFh ; преобразование отрицательного значения в EAX к прямому коду
m1: ; EAX - результат сложения в прямом коде

Флаг вспомогательного (или дополнительного ) переноса EFLAGS.AF помогает манипулировать данными в двоично-десятичном формате (упакованный BCD-формат ). Он устанавливается, если при сложении возникает перенос из младшей тетрады в старшую тетраду младшего байта результата. Используя команду DAA сразу же вслед за командой ADC , можно произвести так называемую десятичную коррекцию результата сложения и получить сумму в таком же упакованном BCD-формате , как и исходные слагаемые.

Команда ADC с операндом-назначением (DEST ), являющимся переменной в памяти, может использоваться совместно с префиксом блокировки LOCK , который обеспечит атомарное исполнение команды.