Команды сравнения и условные переходы. Безусловный переход




ЦИКЛЫС ИСПОЛЬЗОВАНИЕМ АССЕМБЛЕРНЫХ ВСТАВОК

  1. Цикл с постусловием (эквивалент do{}while)
loop_start: /* начало цикла */ /* вот тут находится тело цикла */ cmpl... /* что-то с чем-то сравнить для принятия решения о выходе из цикла */ je loop_end /* подобрать соответствующую команду условного перехода для выхода из цикла */ jmp loop_start /* иначе повторить цикл снова */loop_end:

 

  1. Цикл с предусловием (эквивалент while(){})
loop_start: /* начало цикла */ cmpl... /* что-то с чем-то сравнить для принятия решения о выходе из цикла */ je loop_end /* подобрать соответствующую команду условного перехода для выхода из цикла */ /* вот тут находится тело цикла */ jmp loop_start /* перейти к проверке условия цикла */loop_end:

Команда loop

Синтаксис:

loop метка

Принцип работы:

§ уменьшить значение регистра %ecx на 1;

§ если %ecx = 0, передать управление следующей за loop команде;

§ если %ecx ≠ 0, передать управление на метку.

Напишем программу для вычисления суммы чисел от 1 до 10 (конечно же, воспользовавшись формулой суммы арифметической прогрессии, можно переписать этот код и без цикла — но ведь это только пример).

Команды сравнения и условные переходы. Безусловный переход

Команда loop неявно сравнивает регистр %ecx с нулём. Это довольно удобно для организации циклов, но часто циклы бывают намного сложнее, чем те, что можно записать при помощиloop. К тому же нужен эквивалент конструкции if(){}. Вот команды, позволяющие выполнять произвольные сравнения операндов:

cmp операнд_2, операнд_1

Команда cmp выполняет вычитание операнд_1операнд_2 и устанавливает флаги. Результат вычитания нигде не запоминается.

Сравнили, установили флаги, — и что дальше? А у нас есть целое семейство jump-команд, которые передают управление другим командам. Эти команды называются командами условного перехода. Каждой из них поставлено в соответствие условие, которое она проверяет. Синтаксис:

jcc метка

Команды jcc не существует, вместо cc нужно подставить мнемоническое обозначение условия.

Мнемоника Английское слово Смысл Тип операндов
e equal равенство любые
n not инверсия условия любые
g greater больше со знаком
l less меньше со знаком
a above больше без знака
b below меньше без знака

Таким образом, je проверяет равенство операндов команды сравнения, jl проверяет условие операнд_1 < операнд_2 и так далее. У каждой команды есть противоположная: просто добавляем букву n:

§ je — jne: равно — не равно;

§ jg — jng: больше — не больше.

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

Команда Состояние проверяемых флагов Условие перехода
JA CF = 0 и ZF = 0 если выше
JAE CF = 0 если выше или равно
JB CF = 1 если ниже
JBE CF = 1 или ZF = 1 если ниже или равно
JC CF = 1 если перенос
JE ZF = 1 если равно
JZ ZF = 1 если 0
JG ZF = 0 и SF = OF если больше
JGE SF = OF если больше или равно
JL SF <> OF если меньше
JLE ZF=1 или SF <> OF если меньше или равно
JNA CF = 1 и ZF = 1 если не выше
JNAE CF = 1 если не выше или равно
JNB CF = 0 если не ниже
JNBE CF=0 и ZF=0 если не ниже или равно
JNC CF = 0 если нет переноса
JNE ZF = 0 если не равно
JNG ZF = 1 или SF <> OF если не больше
JNGE SF <> OF если не больше или равно
JNL SF = OF если не меньше
JNLE ZF=0 и SF=OF если не меньше или равно
JNO OF=0 если нет переполнения
JNP PF = 0 если количество единичных битов результата нечетно (нечетный паритет)
JNS SF = 0 если знак плюс (знаковый (старший) бит результата равен 0)
JNZ ZF = 0 если нет нуля
JO OF = 1 если переполнение
JP PF = 1 если количество единичных битов результата четно (четный паритет)
JPE PF = 1 то же, что и JP, то есть четный паритет
JPO PF = 0 то же, что и JNP
JS SF = 1 если знак минус (знаковый (старший) бит результата равен 1)
JZ ZF = 1 если ноль

Логические условия "больше" и "меньше" относятся к сравнениям целочисленных значений со знаком, а "выше и "ниже" — к сравнениям целочисленных значений без знака. Если внимательно посмотреть, то у многих команд можно заметить одинаковые значения флагов для перехода. Это объясняется наличием нескольких ситуаций, которые могут вызвать одинаковое состояние флагов. В этом случае с целью удобства ассемблер допускает несколько различных мнемонических обозначений одной и той же машинной команды условного перехода. Эти команды ассемблера по действию абсолютно равнозначны, так как это одна и та же машинная команда. Изначально в микропроцессоре i8086 команды условного перехода могли осуществлять только короткие переходы в пределах -128...+127 байт, считая от следующей команды. Начиная с микропроцессора i386, эти команды уже могли выполнять любые переходы в пределах текущего сегмента команд. Это стало возможным за счет введения в систему команд микропроцессора дополнительных машинных команд. Для реализации межсегментных переходов необходимо комбинировать команды условного перехода и команду безусловного перехода jmp. При этом можно воспользоваться тем, что практически все команды условного перехода парные, то есть имеют команды, проверяющие обратные условия.
Применение jcxz/jecxz:

Команда Состояние флагов в eflags/flags Условие перехода
JCXZ не влияет если регистр CX=0
JECXZ не влияет если регистр ECX=0

Команду jcxz/jecxz удобно использовать со всеми командами, использующими регистр ecx/cx для своей работы. Это команды организации цикла и цепочечные команды. Очень важно отметить то, что команда jcxz/jecxz, в отличие от других команд перехода, может выполнять только близкие переходы в пределах -128...+127 байт, считая от следующей команды. Поэтому для нее особенно актуальна проблема передачи управления далее чем в указанном диапазоне. Для этого можно привлечь команду безусловного перехода jmp. Например, команду jcxz/jecxz можно использовать для предварительной проверки счетчика цикла в регистре cx для обхода цикла, если его счетчик нулевой.

 

Кроме команд условного перехода, область применения которых ясна сразу, также существует команда безусловного перехода. Эта команда чем-то похожа на оператор goto языка Си. Синтаксис:

jmp адрес

Эта команда передаёт управление на адрес, не проверяя никаких условий. Заметьте, что адрес может быть задан в виде непосредственного значения (метки), регистра или обращения к памяти.


Примеры.

  1. Нахождение максимального значения в массиве

int max_a (int *a, int n)

{

int i,max=0;

for (i=0;i<n;i++)

{

asm volatile ("movl %[Max], %%eax\n"

"movl %[array], %%ebx\n"

"cmpl %%eax, %%ebx\n" //ebx<eax

"jbe less\n"

"movl %%ebx, %%eax\n"

"less:\n"

"movl %%eax,%[output]\n"

:[output]"=b"(max)

: [array]"d"(a[i]),[Max]"b"(max)

 

);

}

return max;

}

  1. Вычисление факториала

int factorial(int n)

{

int res;

asm volatile ("movl %[n], %%ebx\n"

"movl $1, %%eax\n"

"loop_start:\n"

"cmpl $0, %%ebx \n"

"jne not_zero\n"

"jmp loop_end\n"

"not_zero:\n"

"mull %%ebx\n"

"sub $1,%%ebx\n"

"jmp loop_start\n"

"loop_end:\n"

"movl %%eax,%[output]\n"

:[output]"=b"(res)

: [n]"d"(n)

);

return res;

}



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-08-20 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: