Ветвление программы и условные конструкции

Последнее обновление: 18.07.2023

Условные конструкции позволяют направить действие программы по одному из путей в зависимости от определенного условия. В языке ассемблера нет подобных конструкций в отличие от языков высокого уровня. Однако, используя сравнение значения флагов, метки и переходы, мы можем сами определить подобные конструкции.

Имитация конструкции if..else

Во многих распространеных языках высокого уровня есть конструкция if..else, которая в зависимости от условия выполняет те или иные действия. С помощью бейсикоподобного синтаксиса обобщенно эту конструкцию можно представить следующим образом:

IF условие THEN
 выполняемые действия, если условие верно
ELSE
 выполняемые действия, если условие НЕ верно
END IF

Или конструкция if..else в большинстве сиподобных языков

if(условие)
{
 выполняемые действия, если условие верно
}
else 
{
 выполняемые действия, если условие НЕ верно
}

Например, сначала возьмем простейшую форму конструкции if, которая сравнивает два числа и, если они равны, устанавливает некоторую переменную. Например, на сиподобном языке это выглядело бы так:

if(a == b)
{
    Xn = Xn + 1;
} 

Интуитивно мы могли бы определить подобную конструкцию на языке ассемблера следующим образом. Вначале указываются операторы, которые оценивают выражение - инструкция CMP. Если условие верно, выполняют переход, к метке, где выполняются собственно действия конструкции if. Если условие неверно, выполняем переход к метке, которая выступает в качестве завершения конструкции if. Пример:

.global _start

_start:
    mov x0, #1      // устанавливаемый в конструкции if регистр
    mov x1, #2      // a = 4
    mov x2, #4      // b = 4
begin_if:
    cmp x1, x2      // сравниваем два числа на неравенство
    b.eq equal      // если x1 == x2, переход к метке equal
    b end_if          // если x1 != x2 , то выходим из конструкции if
equal:              // собственно действия конструкции if
    add x0, x0, #1  // если x1 == x2, то x0 = x0 + 1
end_if:
    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Здесь условная конструкция if располагается между метками begin_if и end_if. Допустим, мы хотим увеличить на 1 значение регистра Х0, если регистры Х1 и Х2 равны. Сначала сравниваем регистры Х1 и Х2 инструкцией CMP.

begin_if:
    cmp x1, x2

Далее проверяем условие EQ (что регистры Х1 и Х2 равны):

b.eq equal

Если регистры равны, переходим к метке equal, на которую проецируются собственно действия конструкции if - увеличение значения в регистре Х0

equal:              // собственно действия конструкции if
    add x0, x0, #1

Однако если условие не верно (числа Х1 и Х2 не равны), то инструкцией b выходим из конструкции if - переходим к метке end_if

b end_if 

На первый взгляд в этой программе все замечательно, условия проверяются, действия выполняются, программа работает корректно. Но она не оптимальна. В примере выше мы используем две инструкции перехода. И одна из них избыточна. Поэтому в общем случае подобные условные конструкции делают иначе, а именно наоборот - проверяют противоположное условие. И если оно верно, то выполняется переход к конце конструкции if. Если же условия НЕ верно, выполняются действия конструкции ifЖ

.global _start

_start:
    mov x0, #1      // устанавливаемый в конструкции if регистр
    mov x1, #4      // a = 4
    mov x2, #4      // b = 4
begin_if:
    cmp x1, x2      // сравниваем два числа на неравенство
    b.ne end_if      // если x1 != x2, то выходим из конструкции if
    add x0, x0, #1  // если x1 == x2, то x0 = x0 + 1
end_if:
    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Таким образом, по сравнению с первым вариантом программа стала проще, мы избавились от одной метки и одной инструкции перехода.

if..else

Конструкция if во многих языках также позволяет задать альтернативные условия (обычно для этого применяется оператор else). В этом случае в ассемблере надо использовать дополнительную метку, на которую будут проецироваться альтернативные действия

begin_if
    cmp X, Y            // проверяем условие
    b else              // переход к метке else, если условие не верно
    действия, если условие верно
    b end_if            // выход из конструкции if  
else: 
    действия, если условие не верно
end_if:

Например, если условие верно, прибавим 1 к X0, а если не верно, вычтем 1:

.global _start

_start:
    mov x0, #2      // устанавливаемый в конструкции if регистр
    mov x1, #4     
    mov x2, #4      

begin_if:
    cmp x1, x2      // сравниваем x1 и x2
    b.ne else_if    // если условие не верно (x1 != x2) - к метке else_if
    add x0, x0, 1   // если x1 == x2
    b end_if        // в конец конструкции if
else_if:            // альтернативные действия, если условие не верно
    sub x0, x0, 1      // если x1 != x2
end_if:
    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Здесь, если условие не верно (a и b не равны), то переходим к метке else_if, после которой определено альтернативное действие.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850