При выполнении программы специальный регистр-указатель инструкции или %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