Условные конструкции позволяют направить действие программы по одному из путей в зависимости от определенного условия. В языке ассемблера нет подобных конструкций в отличие от языков высокого уровня. Однако, используя сравнение значения флагов, метки и переходы, мы можем сами определить подобные конструкции.
Во многих распространеных языках высокого уровня есть конструкция if..else, которая в зависимости от условия выполняет те или иные действия. С помощью бейсикоподобного синтаксиса обобщенно эту конструкцию можно представить следующим образом:
IF условие THEN выполняемые действия, если условие верно ELSE выполняемые действия, если условие НЕ верно END IF
Или конструкция if..else в большинстве сиподобных языков
if(условие) { выполняемые действия, если условие верно } else { выполняемые действия, если условие НЕ верно }
Например, сначала возьмем простейшую форму конструкции if, которая сравнивает два числа и, если они равны, устанавливает некоторую переменную. Например, на сиподобном языке это выглядело бы так:
if(a == b) { eax = 1; }
Чтобы определить подобную конструкцию на языке ассемблера, вначале указываются операторы, которые оценивают выражение, а затем выполняют переход, если условие неверно.
.data a dword 22 b dword 22 .code main proc mov eax, a begin_if: cmp eax, b ; сравниваем a и b jne end_if ; если a и b не равны - к метке end_if mov eax, 1 ; если a и b равны end_if: ret main endp end
Для большей наглядности здесь определена необязательная метка begin_if, которая условно определяет начало конструкции. С помощью инструкции cmp
сравниваем два значения и далее,
если два числа не равны, переходим к метке end_if, которая знаменует конец конструкции.
Конструкция if во многих языках также позволяет задать альтернативные условия (обычно для этого применяется оператор else
). В этом случае в ассемблере надо использовать
дополнительную метку, на которую будут проецироваться альтернативные действия
cmp X, Y ; проверяем условие jcc ElseCode ; если условие не верно действия, если условие верно jmp EndOfIf ElseCode: действия, если условие не верно EndOfIf:
Например, если условие верно, в EAX поместим 1, если не верно - 0:
.data a dword 24 b dword 22 .code main proc mov eax, a begin_if: cmp eax, b ; сравниваем a и b jne else_if ; если условие не верно - к метке else_if mov eax, 1 ; если a и b равны jmp end_if ; в конец конструкции id else_if: mov eax, 0 ; если a и b не равны end_if: ret main endp end
Здесь, если условие не верно (a и b не равны), то переходим к метке else_if, после которой определено альтернативное действие.
Когда условие очень простое, то его довольно легко описать на языке ассемблера. Однако если условие комплексное и состоит из ряда простых, то это может привести к значительному усложнению кода ассемблера.
Например, возьмем условие, которое состоит из двух подусловий, объединенных операцией AND:
if((a == b) && (c != d)) {действия}
то есть, условие истинно, если одновременно a равно b и c не равно d. Фактически мы можем представить это выражение как:
if(a == b) if(c != d) {действия}
С точки зрения ассемблера нам надо последовательно проверить все условия, которые связаны операцией AND:
.data a dword 22 b dword 22 c dword 24 d dword 25 .code main proc begin_if: mov eax, a cmp eax, b ; (a==b) jne end_if ; если первое условие не верно mov eax, c cmp eax, d ; (c!=d) je end_if ; если второе условие не верно mov eax, 1 ; если оба условия верны end_if: ret main endp end
То есть проверяем первое условие. Если оно неверно, переходим к концу конструкции if. Если первое условие верно, переходим к проверке второго условия. Если второе условие неверно, переходим к концу конструкции if. Если второе условие верно, выполняем указанные действия.
Другой распространенный способ объединения условий представляет операция OR или логическое ИЛИ:
if((a == b) || (c != d)) {действия}
то есть, условие истинно, если или a равно b, или c не равно d. Фактически мы можем представить это выражение как:
if(a == b) {действия} else if(c != d) {действия}
Если верно одно из условий, то выполняются те же самые действия.
С точки зрения ассемблера нам надо последовательно проверить все условия, которые связаны операцией OR:
.data a dword 22 b dword 22 c dword 24 d dword 25 .code main proc begin_if: mov eax, a cmp eax, b ; (a==b) je do_if ; если первое условие верно переходим к do_if mov eax, c cmp eax, d ; (c != d) je end_if ; если второе условие не верно (то есть если с == d), выходим do_if: mov eax, 1 ; если одно из условий верно end_if: ret main endp end
Сначала проверяем первое условие. Если оно верно, переходим к выполнению действий. Если первое условие неверно, проверяем второе условие. Если второе условие верно, переходим к выполнению действий. Если второе условие тоже не верно, переходим к концу конструкции.
На основе выше указанной информации мы можем переложить на ассемблер более сложные условия, например, которые сочетают операции AND и OR:
if(((a == b) && (c != d)) || (e == f)) {действия}
В данном случае общее условие истинно, если либо верно подусловие (a == b) && (c != d)
, либо (e == f)
. При составлении программы на языке ассемблера целесообразнее
вначале проверить третье условие:
.data a dword 22 b dword 22 c dword 23 d dword 24 e dword 25 f dword 26 .code main proc begin_if: mov eax, e cmp eax, f ; (e==f) je do_if ; если третье условие верно переходим к do_if mov eax, a cmp eax, b ; (a==b) jne end_if ; если первое условие не верно mov eax, c cmp eax, d ; (c!=d) je end_if ; если второе условие не верно do_if: mov eax, 1 ; если одно из условий верно end_if: ret main endp end
То есть вначале проверяем третье условие. Если оно верно, то проверка первых двух условие не имеет смысла, и поэтому переходим к выполнению действий в метку do_if. Если третье условие не верно, то последовательно проверяем первое и второе условие. Если одно из них неверно, то переходим к концу конструкции в метке end_if.
Если нам важен порядок выполнения, то мы могли бы написать так:
.data a dword 21 b dword 22 c dword 23 d dword 24 e dword 25 f dword 26 .code main proc begin_if: mov eax, a cmp eax, b ; (a==b) jne or_if ; если первое условие не верно mov eax, c cmp eax, d ; (c!=d) jne do_if ; если второе условие верно or_if: mov eax, e cmp eax, f ; (e==f) jne end_if ; если третье условие верно переходим к do_if do_if: mov eax, 1 ; если одно из условий верно end_if: ret main endp end
Проверяем первое условие. Если оно неверно, переходим к метке or_if к проверке третьего условия. Если первое условие верно, переходим к проверке второго условия. Если второе условие верно, то проверять третье условие смысла нет, и переходим к метке do_if и выполнению указанных инструкций.