К условиям в ассемблере относятся инструкции циклов и ветвления. Эти инструкции могут изменять поток выполнения кода в программе.
Типы прыжков
Есть 2 типа выполнения условий в ассемблере:
Прыжок без условия (или «безусловный прыжок») — выполняется инструкцией JMP. Выполнение данной инструкции часто включает в себя передачу управления в адрес инструкции, которая не следует за выполняемой в настоящее время инструкцией. Результатом передачи управления может быть выполнение нового набора инструкций или повторное выполнение текущих инструкций.
Прыжок с условием (или «условный прыжок») — выполняется с помощью инструкций типа J<условие>
и зависит от самого условия. Условные инструкции, изменяя значение смещения в регистре IP, передают управление, прерывая последовательный поток выполнения кода.
Прежде чем разбираться с этими двумя типами инструкций детально, давайте рассмотрим инструкцию CMP.
Инструкция CMP
Инструкция CMP (от англ. «COMPARE») сравнивает два операнда. Фактически, она выполняет операцию вычитания между двумя операндами для проверки того, равны ли эти операнды или нет. Используется вместе с инструкцией условного прыжка.
Синтаксис инструкции CMP:
CMP назначение, источник
Инструкция CMP сравнивает два числовых поля. Операнд назначения может находиться либо в регистре, либо в памяти. Исходным операндом (источник
) могут быть константы, регистры или память. Например:
1 2 3 4 5 |
CMP DX, 00 ; сравниваем значение регистра DX с нулем JE L7 ; если true, то переходим к метке L7 . . L7: ... |
Инструкция CMP часто используется для проверки того, достигла ли переменная-счетчик максимального количества раз выполнения цикла или нет. Например:
1 2 3 |
INC EDX CMP EDX, 10 ; сравниваем, достиг ли счетчик значения 10 или нет JLE LP1 ; если его значение меньше или равно 10, то тогда переходим к LP1 |
Прыжок без условия
Как мы уже говорили, безусловный прыжок выполняется инструкцией JMP, которая включает в себя имя метки, куда следует перебросить точку выполнения программы:
JMP label
В следующем примере мы рассмотрим использование инструкции JMP:
1 2 3 4 5 6 7 8 |
MOV AX, 00 ; инициализируем регистр AX значением 0 MOV BX, 00 ; инициализируем регистр BX значением 0 MOV CX, 01 ; инициализируем регистр CX значением 1 L20: ADD AX, 01 ; выполняем инкремент регистра AX ADD BX, AX ; добавляем AX к BX SHL CX, 1 ; сдвиг влево регистра CX, что, в свою очередь, удваивает его значение JMP L20 ; повторно выполняем стейтменты |
Прыжок с условием
Если при выполнении операции условного прыжка выполняется обозначенное условие, то точка выполнения программы переносится в указанную инструкцию. Существует множество инструкций условного прыжка, в зависимости от условия и данных.
Ниже приведены инструкции условного прыжка, используемые для данных со знаком в арифметических операциях:
Инструкция | Описание | Тестируемые флаги |
JE/JZ | Jump Equal (равно) или Jump Zero (ноль) | ZF |
JNE/JNZ | Jump Not Equal (не равно) или Jump Not Zero (не ноль) | ZF |
JG/JNLE | Jump Greater (больше) или Jump Not Less/Equal (не меньше/равно) | OF, SF, ZF |
JGE/JNL | Jump Greater/Equal (больше/равно) или Jump Not Less (не меньше) | OF, SF |
JL/JNGE | Jump Less (меньше) или Jump Not Greater/Equal (не больше/равно) | OF, SF |
JLE/JNG | Jump Less/Equal (меньше/равно) или Jump Not Greater (не больше) | OF, SF, ZF |
В следующей таблице приведены инструкции условного прыжка, используемые для данных без знака в логических операциях:
Инструкция | Описание | Тестируемые флаги |
JE/JZ | Jump Equal (равно) или Jump Zero (ноль) | ZF |
JNE/JNZ | Jump Not Equal (не равно) или Jump Not Zero (не ноль) | ZF |
JA/JNBE | Jump Above (больше) или Jump Not Below/Equal (не меньше/равно) | CF, ZF |
JAE/JNB | Jump Above/Equal (больше/равно) или Jump Not Below (не меньше) | CF |
JB/JNAE | Jump Below (меньше) или Jump Not Above/Equal (не больше/равно) | CF |
JBE/JNA | Jump Below/Equal (меньше/равно) или Jump Not Above (не больше) | AF, CF |
Следующие инструкции условного прыжка имеют специальное использование и проверяют значение флагов:
Инструкция | Описание | Тестируемые флаги |
JCXZ | Jump если CX равно Zero | none |
JC | Jump если Carry (перенос) | CF |
JNC | Jump если No Carry (нет переноса) | CF |
JO | Jump если Overflow (переполнение) | OF |
JNO | Jump если No Overflow (нет переполнения) | OF |
JP/JPE | Jump Parity или Jump Parity Even (если чётность) | PF |
JNP/JPO | Jump No Parity или Jump Parity Odd (если нечётность) | PF |
JS | Jump Sign (отрицательное значение) | SF |
JNS | Jump No Sign (положительное значение) | SF |
Пример синтаксиса набора инструкций типа J<условие>
:
1 2 3 4 5 6 7 8 |
CMP AL, BL JE EQUAL CMP AL, BH JE EQUAL CMP AL, CL JE EQUAL NON_EQUAL: ... EQUAL: ... |
В качестве примера рассмотрим следующую программу, которая определяет и выводит на экран наибольшую из 3 целочисленных переменных:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
section .text global _start ; должно быть объявлено для использования gcc _start: ; сообщаем линкеру входную точку mov ecx, [num1] cmp ecx, [num2] jg check_third_num mov ecx, [num2] check_third_num: cmp ecx, [num3] jg _exit mov ecx, [num3] _exit: mov [largest], ecx mov ecx,msg mov edx, len mov ebx,1 ; файловый дескриптор (stdout) mov eax,4 ; номер системного вызова (sys_write) int 0x80 ; вызов ядра mov ecx,largest mov edx, 2 mov ebx,1 ; файловый дескриптор (stdout) mov eax,4 ; номер системного вызова (sys_write) int 0x80 ; вызов ядра mov eax, 1 int 80h section .data msg db "The largest number is: ", 0xA,0xD len equ $- msg num1 dd '47' num2 dd '22' num3 dd '31' segment .bss largest resb 2 |
Результат выполнения программы:
The largest number is:
47
У меня у одного будет при:
num1 dd '47'
num2 dd '22'
num3 dd '51'
'47'?
И да, я не путаю? Тут сравнение не чисел, а их результата в строке?