Базовые конструкции

Условные конструкции

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

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

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

Во многих распространеных языках высокого уровня есть конструкция 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

Например, возьмем условие, которое состоит из двух подусловий, объединенных операцией 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

Другой распространенный способ объединения условий представляет операция 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

На основе выше указанной информации мы можем переложить на ассемблер более сложные условия, например, которые сочетают операции 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 и выполнению указанных инструкций.

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