Переходы

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

При выполнении программы специальный регистр-указатель инструкции или %rip указывает на адрес памяти, по которому будет извлекаться следующая для выполнения инструкция. Во время выполнения каждой инструкции процессор увеличивает указатель инструкции, чтобы регистр RIP указавал на следующую инструкцию — ту, которая находится сразу после текущей инструкции.

Инструкции перехода указывают процессору изменить ход выполнения программы, установив для указателя инструкции значение, отличное от того, которое процессор собирался установить. Самая простая форма инструкций перехода — это инструкция JMP , которая выполняет безусловный переход и имеет следующие формы:

jmp метка

После инструкции указывается метка, к которой надо перейти. Названия меток произвольные. В языках высокого уровня этой инструкции соответствует оператор goto. Например:

.globl _start
.text
_start:
    movq $11, %rdi      # RDI = 11
    jmp exit            # переходим к метке exit
    movq $22, %rdi      # не выполняется
exit:                   # метка exit
    movq $60, %rax
    syscall

Здесь выполнение программы начинается с копирования в регистр RDI числа 11. Затем инструкции безусловного перехода jmp осуществляет переход к метке exit

jmp exit

В итоге последующая инструкция mov, которая помещается в регистр RDI число 22, НЕ выполняется

movq $22, %rdi

А выполняются инструкции, которые помещаются после метки exit. Для установки метки после ее имени указывается двоеточие:

exit:                   # метка exit
    movq $60, %rax
    syscall

То есть в итоге в регистре RDI будет число 11.

Непрямые переходы

С помощью инструкции jmp можно выполнять переходы по определенному адресу - обычно адресу метки. Но также инструкция может выполнять непрямые переходы - в этом случае инструкции передается регистр или переменная, которые хранят некоторый адрес. И по этому адресу идет переход. Например:

.globl _start
.data 
pointer: .quad exit     # переменная pointer хранит адрес метки exit
.text
_start:
    movq $10, %rdi        
    jmp *pointer    # переход по адресу, который хранится в переменной pointer
    movq $5, %rdi   # эта инструкция не выполняется
exit:
    movq $60, %rax
    syscall

Здесь переменная pointer хранит адрес метки exit. Для теста в регистр RDI помещаем число 10. Затем выполняем непрямой переход по адресу, который хранится в переменной pointer. При этом перед именем переменной указывается символ звездочка:

jmp *pointer

Аналогично можно переходить по адресу, который хранится в регистре. В этом случае перед названием регистра также указывается звездочка:

.globl _start
.text
_start:
    movq $exit, %rbx    # в регистре RBX адрес метки exit
    movq $11, %rdi
    jmp *%rbx       # переход по адресу, который хранится в регистре RBX
    movq $6, %rdi 
exit:
    movq $60, %rax
    syscall

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