Поход на рынок, как правило, заканчивается покупкой какого-либо товара. Если мы хотим купить несколько единиц товара одного наименования, то продавец посчитает нам итоговую сумму с использованием простейшего компьютера – микрокалькулятора. В аналогии с ассемблером при умножении товаров программа микрокалькулятора будет оперировать с числами без знака, поскольку нельзя купить минус три пури или минус пять круассанов. […]
CMP
Синтаксис | CMP приёмник,источник |
Машинный код | 3C ib — CMP AL,imm8 3D iw — CMP AX,imm16 3D id — CMP EAX,imm32 80 /7 ib — CMP r/m8,imm8 81 /7 iw — CMP r/m16,imm16 81 /7 id — CMP r/m32,imm32 83 /7 ib — CMP r/m16,imm8 83 /7 ib — CMP r/m32,imm8 38 /r — CMP r/m8,r8 39 /r — CMP r/m16,r16 39 /r — CMP r/m32,r32 3A /r — CMP r8,r/m8 3B /r — CMP r16,r/m16 3B /r — CMP r32,r/m32 |
Описание | Сравнение. |
Действие | Инструкция CMP сравнивает 2 операнда. Основное применение инструкции – проверка условий в циклах. CMP вычитает один операнд от другого, затем сравнивает, являются операнды равными или нет (см. команда SUB). Исходные операнды не меняются. Также используется для условных переходов по меткам. |
Флаги | OF=r SF=r ZF=r AF=r PF=r CF=r |
Пример использования инструкции CMP:
1 2 3 4 5 | CMP AX,0 ; Сравнить AX с 0 JE proc ; Если ноль, переход на метку proc ... ... proc: ... |
CMP часто используется для сверки счетчика, то есть сравнения числа повторений цикла с условием. Рассмотрим типичный случай:
1 2 | cmp cx,0xA ; Проверка, достиг ли счетчик 16 Jle lp1 ; Если счетчик равен или меньше 16, перейти на метку lp1 |
SBB
Синтаксис | SBB приемник,источник |
Машинный код | 1C ib — SBB AL,imm8 1D iw — SBB AX,imm16 1D id — SBB EAX,imm32 80 /3 ib — SBB r/m8,imm8 81 /3 iw — SBB r/m16,imm16 81 /3 id — SBB r/m32,imm32 83 /3 ib — SBB r/m16,imm8 83 /3 ib — SBB r/m32,imm8 18 /r — SBB r/m8,r8 19 /r — SBB r/m16,r16 19 /r — SBB r/m32,r32 1A /r — SBB r8,r/m8 1B /r — SBB r16,r/m16 1B /r — SBB r32,r/m32 |
Описание | Вычитание с заёмом. |
Действие | Вычитание двух целочисленных двоичных операндов с учётом флага CF. |
Флаги | OF=r SF=r ZF=r AF=r PF=r CF=r |
Команда SBB дополняет команду SUB при выполнени вычитания чисел частями. Состояние флага CF представляет собой заём от предыдущего вычитания. Приёмник = приёмник — (источник + CF)
Пример использования команды SBB для вычитания операнда размером в слово (2 байта) из двойного слова (4 байта):
1 2 3 4 5 6 7 8 9 | mov ax, word[a] ;ax = 0x680 mov bx, word[a+2] ;bx = 0x7700 sub ax,[b] ;0x680 - 0x43F2 = 0xC28E sbb bx,0 ;0x7700 - (0 + 1) = 0x76FF ;ax:bx = 0xC28E76FF ;------ Переменные ------ a dd 0x77000680 b dw 0x43F2 |
Регистры процессоров ограничены в разрядности архитектурой процессора (как правило, x86/64), поэтому сложение чисел, как из реального мира, так и из виртуального в ассемблере имеет дополнительные нюансы. В предыдущем Уроке 9. Сложение и вычитание операции сложения и вычитания выполнялись только в границах размеров регистров. Сложение операндов превышающих размеры регистров приводит к переполнению и установке флага CF. […]
NEG
Синтаксис | NEG операнд |
Машинный код | F6 /3 — NEG r/m8 F7 /3 — NEG r/m16 F7 /3 — NEG r/m32 |
Описание | Изменение знака. |
Действие | Команда вычисляет двоичное дополнение операнда. |
Флаги | Если операнд равен нулю: CF=0 OF=r SF=r ZF=r AF=r PF=r. Если операнд не равен нулю: CF=1 OF=r SF=r ZF=r AF=r PF=r. |
Команда NEG меняет знак операнда, преобразуя его значение в дополнительный код. Инструкция имеет смысл только для чисел со знаком, поскольку преобразование теряет смысл, если число 1 преобразуется в интерпретируемое беззнаковым число 255 (FF).
По выполнению инструкции устанавливаются флаги, которые характеризуют преобразование. Если произошло преобразование положительного числа в отрицательное, то SF=1, для всех остальных случаев SF=0.
Пример использования команды NEG:
1 2 3 4 5 6 7 8 | ; f = (a + b - 1) * (-a) mov ah,100 ; a = 100 mov al,85 ; b = 85 mov bl,ah ; bl = a neg bl ; bl = -a add ah,al ; a + b dec ah ; a + b - 1 mul bl ; ax = (a + b - 1) * (-a) |
SUB
Синтаксис | SUB приемник,источник |
Машинный код | 2C ib — SUB AL,imm8 2D iw — SUB AX,imm16 2D id — SUB EAX,imm32 80 /5 ib — SUB r/m8,imm8 81 /5 iw — SUB r/m16,imm16 81 /5 id — SUB r/m32,imm32 83 /5 ib — SUB r/m16,imm8 83 /5 ib — SUB r/m32,imm8 28 /r — SUB r/m8,r8 29 /r — SUB r/m16,r16 29 /r — SUB r/m32,r32 2A /r — SUB r8,r/m8 2B /r — SUB r16,r/m16 2B /r — SUB r32,r/m32 |
Описание | Вычитание. |
Действие | Вычитание двух целочисленных двоичных операндов. приёмник = приёмник — источник |
Флаги | OF=r SF=r ZF=r AF=r PF=r CF=r |
Команда SUB вычитает из первого операнда (приёмника) второй операнд. Результат вычитания переписывает значение операнда — приёмника.
Флаг SF имеет значение только для чисел со знаком. SF=1 указывает на отрицательный знак результата. Пример:
1 2 3 | mov ah,100 mov al,127 sub ah,al ; AH = 0xE5 = -27, SF=1 |
Если числа равноразмерные и без знака, то CF=1 будет указывать на некорректный результат (результат ушел в отрицательное значение). Например:
1 2 3 | mov ah,250 mov al,251 sub ah,al ;AH = 0xFF = -1 (число со знаком) и 0xFF = 255 (число без знака). Т.е. результат некорректный |
Для чисел со знаком и при вычитании меньшего по размеру числа от большего (пример, вычитание слова от двойного слова) CF=1 означает, что вычитание выполнилось с заёмом. Инструкция SBB продолжит вычитание с учетом флага CF:
1 2 3 4 5 6 7 8 | mov ax,0x37DD ; Старшая часть уменьшаемого числа mov bx,0x0077 ; Младшая часть уменьшаемого числа mov dx,0x3DDE ; Вычитаемое число sub bx,dx ; Сперва вычитаем от младшей части ; BX = BX - DX = 0xC299. SF=1, CF=1 sbb ax,0 ; Затем вычитаем от старшей части с учетом CF ; AX = AX - 1 = 0x37DC |
После того, как мы изучили механизм представления и обработки чисел процессором, самое время начать знакомство с инструкциями. Ну а к самым простым инструкциям в ассемблере безусловно относятся мнемоники для сложения и вычитания чисел — ADD и SUB. Сложение — команда ADD Инструкция ADD выполняет сложение двух операндов. ADD можно «скармливать» числа со знаком и без […]
ADC
Синтаксис | ADC приемник,источник |
Машинный код | 14 ib — ADC AL,imm8 15 iw — ADC AX,imm16 15 id — ADC EAX,imm32 80 /2 ib — ADC r/m8,imm8 81 /2 iw — ADC r/m16,imm16 81 /2 id — ADC r/m32,imm32 83 /2 ib — ADC r/m16,imm8 83 /2 ib — ADC r/m32,imm8 10 /r — ADC r/m8,r8 11 /r — ADC r/m16,r16 11 /r — ADC r/m32,r32 12 /r — ADC r8,r/m8 13 /r — ADC r16,r/m16 13 /r — ADC r32,r/m32 |
Описание | Сложение с учётом переноса. |
Действие | Сложение двух целочисленных двоичных операндов с учётом флага переноса CF. приёмник = приёмник + источник + CF |
Флаги | OF=r SF=r ZF=r AF=r PF=r CF=r |
При сложении чисел которые в результате дадут больше 16 бит происходит перенос старшего бита, из-за чего флаг CF (carry flag) меняет значение. Команда ADC учитывает значение флага CF предыдущей операции сложения и при вызове складывает операнды и добавляет значение CF (единицу или ноль) к младшему разряду результата.
Пример использования команды adc:
1 2 3 4 5 6 7 8 9 10 11 12 | jmp start x dw 56767 y dw 32000 z dd ? start: mov ax,[x] mov bx,[y] add ax,bx mov word[z],ax ;Сохранение младшей части результата xor ax,ax ;Обнуление ax adc ax,0 ;Если CF=1, он будет перенесен в регистр ax mov word[z+2],ax ;Сохранение старшей части результата |
ADD
Синтаксис | ADD приемник,источник |
Машинный код | 04 ib — ADD AL,imm8 05 iw — ADD AX,imm16 05 id — ADD EAX,imm32 80 /0 ib — ADD r/m8,imm8 81 /0 iw — ADD r/m16,imm16 81 /0 id — ADD r/m32,imm32 83 /0 ib — ADD r/m16,imm8 83 /0 ib — ADD r/m32,imm8 00 /r — ADD r/m8,r8 01 /r — ADD r/m16,r16 01 /r — ADD r/m32,r32 02 /r — ADD r8,r/m8 03 /r — ADD r16,r/m16 03 /r — ADD r32,r/m32 |
Описание | Сложение. |
Действие | Сложение двух целочисленных двоичных операндов. приёмник = приёмник + источник |
Флаги | OF=r SF=r ZF=r AF=r PF=r CF=r |
Команда add выполняет операцию сложения. Результат сложения 2-х аргументов помещается в первый аргумент (приемник). Если результат выходит за диапазон приемника, изменяются флаги CF и OF (переполнение), SF (результат со знаком минус), которые интерпретируются в зависимости от того, являются ли складываемые аргументы числами со знаком или без.
Пример использования команды add:
1 2 3 | mov al,7 mov ah,100 add al,ah ;al = 107; sf=0, zf=0, cf=0 (нет переполнения) |
Со школьной скамьи нас учили, что у чисел бывают отрицательные значения. Дело выглядело просто, записываешь число на бумаге, рисуешь черточку слева и все – положительное число превратилось в отрицательное. Для арифметической операции нужно от положительного числа отнять модуль отрицательного числа. К сожалению, такой подход совершенно не приемлем для машинных вычислений, потому что процессор не разделяет […]