4.1.2. Косвенный переход
При косвенном переходе в команде перехода указывается не адрес перехода, а регистр или ячейка памяти, где этот адрес находится. Содержимое указанного регистра или ячейки памяти рассматривается как абсолютный адрес перехода. Косвенные переходы используются в тех случаях, когда адрес перехода становится известен только во время работы программы.
jmp ebx
4.2. Команды сравнения и условного перехода
Команды условного перехода осуществляют переход, который выполняется только в случае истинности некоторого условия. Истинность условия проверяется по значениям флагов. Поэтому обычно непосредственно перед командой условного перехода ставится команда сравнения, которая формирует значения флагов:
CMP <операнд1>, <операнд2>
Команда сравнения эквивалентна команде SUB за исключением того, что вычисленная разность никуда не заносится. Назначение команды CMP – установка и сброс флагов.
Что касается команд условного перехода, то их достаточно много, но все они записываются единообразно:
Jxx <метка>
Все команды условного перехода можно разделить на три группы.
В первую группу входят команды, которые обычно ставятся после команды сравнения. В их мнемокодах указывается тот результат сравнения, при котором надо делать переход.
Мнемокод
|
Название
|
Условие перехода после команды CMP op1, op2
|
Значения флагов
|
Примечание
|
JE
|
Переход если равно
|
op1 = op2
|
ZF = 1
|
Для всех чисел
|
JNE
|
Переход если не равно
|
op1 ≠ op2
|
ZF = 0
|
JL/JNGE
|
Переход если меньше
|
op1 < op2
|
SF ≠ OF
|
Для чисел со знаком
|
JLE/JNG
|
Переход если меньше или равно
|
op1 ≤ op2
|
SF ≠ OF или ZF = 1
|
JG/JNLE
|
Переход если больше
|
op1 > op2
|
SF = OF и ZF = 0
|
JGE/JNL
|
Переход если больше или равно
|
op1 ≥ op2
|
SF = OF
|
JB/JNAE
|
Переход если ниже
|
op1 < op2
|
CF = 1
|
Для чисел без знака
|
JBE/JNA
|
Переход если ниже или равно
|
op1 ≤ op2
|
CF = 1 или ZF = 1
|
JA/JNBE
|
Переход если выше
|
op1 > op2
|
CF = 0 и ZF = 0
|
JAE/JNB
|
Переход если выше или равно
|
op1 ≥ op2
|
CF = 0
|
Рассмотрим пример: даны две переменные x и y, в переменную z нужно записать максимальное из чисел x и y.
mov eax, x cmp eax, y jge/jae L ; Используем JGE для знаковых чисел и JAE – для беззнаковых mov eax, y L: mov z, eax
Во вторую группу команд условного перехода входят те, которые обычно ставятся после команд, отличных от команды сравнения, и которые реагируют на то или иное значение какого-либо флага.
Мнемокод
|
Условие перехода
|
Мнемокод
|
Условие перехода
|
JZ
|
ZF = 1
|
JNZ
|
ZF = 0
|
JS
|
SF = 1
|
JNS
|
SF = 0
|
JC
|
CF = 1
|
JNC
|
CF = 0
|
JO
|
OF = 1
|
JNO
|
OF = 0
|
JP
|
PF = 1
|
JNP
|
PF = 0
|
Рассмотрим пример: пусть a, b и c – беззнаковые переменные размером 1 байт, требуется вычислить c = a * a + b, но если результат превосходит размер байта, передать управление на метку ERROR.
mov al, a mul al jc ERROR add al, b jc ERROR mov c, al
И, наконец, в третью группу входят две команды условного перехода, проверяющие не флаги, а значение регистра ECX или CX:
JCXZ <метка> ; Переход, если значение регистра CX равно 0 JECXZ <метка> ; Переход, если значение регистра ECX равно 0
Однако эта команда выполняется достаточно долго. Выгоднее провести сравнение с нулём и использовать обычную команду условного перехода.
С помощью команд перехода можно реализовать любые разветвления и циклы.
; if (x > 0) S cmp x, 0 jle L ... ; S L: ; if (x) S1 else S2 cmp x, 0 je L1 ... ; S1 jmp L2 L1: ... ; S2 L2: ; if (a > 0 && b > 0) S cmp a, 0 jle L cmp b, 0 jle L ... ; S L: ; if (a > 0 || b > 0) S cmp a, 0 jg L1 cmp b, 0 jle L2 L1: ... ; S L2: ; if (a > 0 || b > 0 && c > 0) S cmp a, 0 jg L1 cmp b, 0 jle L2 cmp c, 0 jle L2 L1: ... ; S L2: ; while (x > 0) do S L1: cmp x, 0 jle L2 ... ; S jmp L1 L2: ; do S while (x > 0) L: ... ; S cmp x, 0 jg L
4.3. Команды управления циклом
4.3.1. Команда LOOP
Команда LOOP позволяет организовать цикл с известным числом повторений:
mov ecx, n L: ... ... loop L
Команда LOOP требует, чтобы в качестве счётчика цикла использовался регистр ECX. Собственно, команда LOOP вычитает единицу именно из этого регистра, сравнивает полученное значение с нулём и осуществляет переход на указанную метку, если значение в регистре ECX больше 0. Метка определяет смещение перехода, которое не может превышать 128 байт.
При использовании команды LOOP следует также учитывать, что с её помощью реализуется цикл с постусловием, следовательно, тело цикла выполняется хотя бы один раз. Хуже того, если до начала цикла записать в регистр ECX значение 0, то при вычитании единицы, которое выполняется до сравнения с нулём, в регистре ECX окажется ненулевое значение, и цикл будет выполняться 232 раз.
Команда LOOP не относится к самым быстрым командам. В большинстве случаев её можно заменить последовательностью других команд.
4.3.2. Команды LOOPE/LOOPZ и LOOPNE/LOOPNZ
Эти команды похожи на команду LOOP, но позволяют также организовать и досрочный выход из цикла.
LOOPE <метка> ; Команды являются синонимами LOOPZ <метка>
Действие этой команды можно описать следующим образом: ECX = ECX - 1; if (ECX != 0 && ZF == 1) goto <метка>;
До начала цикла в регистр ECX необходимо записать число повторений цикла. Команда LOOPE/LOOPZ, как и команда LOOP ставится в конце цикла, а перед ней помещается команда, которая меняет флаг ZF (обычно это команда сравнения CMP). Команда LOOPE/LOOPZ заставляет цикл повторяться ECX раз, но только если предыдущая команда фиксирует равенство сравниваемых величин (вырабатывает нулевой результат, т.е. ZF = 1).
По какой именно причине произошёл выход из цикла надо проверять после цикла. Причём надо проверять флаг ZF, а не регистр ECX, т.к. условие ZF = 0 может появиться как раз на последнем шаге цикла, когда и регистр ECX стал нулевым.
Команда LOOPNE/LOOPNZ аналогична команде LOOPE/LOOPZ, но досрочный выход из цикла осуществляется, если ZF = 1.
Рассмотрим пример: пусть в регистре ESI находится адрес начала некоторого массива двойных слов, а в переменной n – количество элементов массива, требуется проверить наличие в массиве элементов, кратных заданному числу x, и занести в переменную f значение 1, если такие элементы есть, и 0 в противном случае.
mov ebx, x mov ecx, n mov f, 1 L1: mov eax, [esi] add esi, 4 cdq idiv ebx cmp edx, 0 loopne L1 je L2 mov f, 0 L2:
Do'stlaringiz bilan baham: |