Безусловный и условный переходы

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

Безусловный переход

Наипростейшая форма ветвления представляет инструкция:

B label

которая производит переход к метке label. Метка label рассматривается как смещение относительно текущего регистра и может занимать 26 бит, что позволяет сделать переход на расстояние до 128 мегабайт. Эта инструкция аналогична оператору goto в ряде высокоуровневых языков программирования. Например, бесконечный переход на метку _start:

_start: MOV X1, #1
B _start

Другой пример:

.global _start 
_start: 
    mov x0, 10
    b exit
    mov x0, 33
exit:                  // X0=10
    mov x8, #93       // устанавливаем функцию Linux для выхода из программы
    svc 0             // Вызываем функцию Linux

Здесь инструкция b exit производит переход к метке exit. Поэтому в конце программы в регистре Х0 будет число 10, а не 33.

Переход по адресу в регистре

Также для безусловных переходов в ARM64 есть инструкция BR. Она переходит по адресу в регистре, который передается в качестве операнда инструкции:

.global _start 
_start: 
    mov x0, 11
    ldr x1, =exit   // загружаем в Х1 адрес метки exit
    br x1           // переход по адресу в регистре Х1
    mov x0, 44
exit:                  // X0=10
    mov x8, #93       // устанавливаем функцию Linux для выхода из программы
    svc 0             // Вызываем функцию Linux

Здесь в регистр Х1 с помощью инструкции LDR загружается адрес метки exit

ldr x1, =exit

Затем с помощью инструкции BR происходит переход к адресу, загруженному в Х1.

br x1

Условный переход

Инструкция перехода B выполняет переход к определенной метке, если установлен или сброшен определенный флаг.

B.{condition} label

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

Условие

Флаг

Значение

EQ

Z == 1

Равенство значений

NE

Z == 0

Неравенство значений

CS или HS

C == 1

больше или равно >= (без знака)

CC или LO

C == 0

меньше < (без знака)

MI

N == 1

Значение отрицательное

PL

N == 0

Значение положительное или равно 0

VS

V == 1

Есть переполнение знака

VC

V == 0

Нет переполнения знака

HI

C == 1 && Z == 0 (C-флаг установлен, а Z-флаг сброшен)

больше > (без знака)

LS

!(C == 1 && Z == 0) (C-флаг сброшен, а Z-флаг установлен или сброшен)

меньше или равно <= (без знака)

GE

N == V (N-флаг и V-флаг совпадают)

больше или равно >= (со знаком)

LT

N != V (N-флаг и V-флаг различаются)

>меньше < (со знаком)

GT

Z == 0 && N == V (Z-флаг сброшен, N-флаг и V-флаг совпадают)

больше > (со знаком)

LE

!(Z == 0 && N == V) (Z-флаг установлен, N-флаг и V-флаг различаются)

меньше или равно <= (со знаком)

AL

любое значение

Всегда истинно

Как видно из таблицы, для каждого условия есть обратное условие:

EQ (равно)

NE (не равно)

HS/CS (Флаг переноса установлен)

LO/CC (Флаг переноса сброшен)

MI (Результат отрицательный)

PL (Результат положительный или равен 0)

VS (Переполнение знака)

VC (Нет переполнения знака)

HI (беззнаковое больше)

LS (Беззнаковое меньше или равно)

GE (Больше чем или равно со знаком)

LT (Меньше чем со знаком)

GT (Больше чем со знаком)

LE (Меньше чем или равно со знаком)

Например, нам надо проверить, установлен ли после выполнения сложения флаг переноса. В этом случае мы могли бы написать:

.global _start

_start:
    mov x0, #-1
    mov x1, #3
    adds x0, x0, x1     // x0 = -1 + 3 = 2 

    // проверяем условие CS - установлен флаг переноса C
    b.cs carry  // если флаг установлен - переход к метке carry
    mov x0, 1   // если флаг не установлен, Х0=1
    b exit
carry:
    mov x0, 2   // если флаг установлен, Х0=2
exit:
    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Здесь выполняем сложение -1 + 3. При сложении инструкция ADDS устанавливает флаги. И с помощью инструкции

b.cs carry

проверяем условие CS, то есть, что флаг переноса C установлен. И если он установлен, то переходим к метке carry, на которой в регистр Х0 помещаем число 2.

carry:
    mov x0, 2   // если флаг установлен, Х0=2

Если флаг не установлен, то перехода к метке carry не осуществляется, а выполняются последующие инструкции

mov x0, 1   // если флаг не установлен, Х0=1
b exit

То есть в Х0 помещаем число 1 и переходим к метке exit для завершения программы.

Другой пример - проверим равенство чисел и для этого используем условие EQ:

.global _start

_start:
    mov x0, #3
    mov x1, #3
    subs x0, x0, x1     // x0 = 3 - 3 = 20

    // проверяем условие EQ - установлен флаг нуля
    b.eq equal  // если флаг установлен - переход к метке equal
    mov x0, #255   // если флаг не установлен, Х0=255
    b exit
equal:
    mov x0, #1   // если флаг установлен, Х0=1
exit:
    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Здесь с помощью инструкции SUBS вычитаем из Х0 число в регистре Х1. Если эти числа равны, то результатом будет 0, и соответственно установливается флаг нуля. ПОсле выполнения инструкции мы можем проверить условие EQ

b.eq equal

И если Z-флаг установлен, то есть числа равны, выполнить переход к метке equal.

Специальные инструкции переходов

Как было указано выше, для перехода к метке при соблюдении некоторого условия применяется конструкция

B.{condition} label

В качестве альтернативы можно применять специальные инструкции, которые называются по шаблону:

B{condition} label

В частности, это инструкции:

  • BEQ label: переход, если Z = 1 (значения равны)

  • BNE label: переход, если Z = 0 (значения не равны)

  • BCS/BHS label: переход, если C = 1 (первое значение больше или равно, беззнаковое сравнение)

  • BCC/BLO label: переход, если C = 0 (первое значение меньше, беззнаковое сравнение)

  • BMI label: переход, если N = 1

  • BPL label: переход, если N = 0

  • BVS label: переход, если V = 1

  • BVC label: переход, если V = 0

  • BHI label: переход, если C = 1 и Z = 0 (первое значение больше, беззнаковое сравнение)

  • BLS label: переход, если C = 0 и Z = 1 (первое значение меньше или равно, беззнаковое сравнение)

  • BGE label: переход, если N = V (первое значение больше или равно, сравнение со знаком)

  • BLT label: переход, если N != V (первое значение меньше, сравнение со знаком)

  • BGT label: переход, если Z = 0 и N = V (первое значение больше, сравнение со знаком)

  • BLE label: переход, если или Z = 1, или N = !V (первое значение меньше или равно, сравнение со знаком)

Применение на примере инструкции BEQ:

.global _start

_start:
    mov x0, #4
    mov x1, #4
    cmp x0, x1
    beq equal       // если  x0 == x1, переход к метке equal

    mov x0, #1          // если x1 != x1 , то x0 = 1
    b exit
equal:
    mov x0, #2         // если x1 == x1, то x0 = 2
exit:
    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Производительность при использовании переходов

При использовании переход следует учитывать процесс выполнения инструкции 64-битного ARM-процессора. В частности, в общем случае выполнение инструкции требует 3 тактов/циклов процессора (clock cycles):

  1. Загрузка инструкции из памяти в процессор

  2. Декодирование инструкции

  3. Выполнение инструкции

Процессор может работать над тремя инструкциями одновременно, только на разных этапах, например, одну загружает, другую декодирует, третью выполняет. Что ускоряет выполнение программ. Но использование переходов вносит коррективы в этот процесс. Так, при использовании переходов, если следущая инструкция уже декодирована, а находящая после нее инструкция загружена и готова к декодированию, переход полностью обнуляет эту работу. После перехода процессор заново загружает инструкцию, декодирует ее и выполняет. Конкретный процессор может сглаживать подобный недостаток за счет ряда техник, в частности, он может предугадывать направление перехода. Однако в общем случае злоупотребление переходами может привести к потере производительности.

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