jal

jal

RISC-V Ассемблер Ссылка

lyszt.net охватывает jal и другие инструкции RISC-V более подробно.

Формат кодирования

R
31–25funct7
24–20rs2
19–15rs1
14–12funct3
11–7rd
6–0opcode
I
31–20imm[11:0]
19–15rs1
14–12funct3
11–7rd
6–0opcode
S
31–25imm[11:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:0]
6–0opcode
B
31–25imm[12,10:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:1,11]
6–0opcode
U
31–12imm[31:12]
11–7rd
6–0opcode
J
31–12imm[20,10:1,11,19:12]
11–7rd
6–0opcode

Описание

jal вызывает функцию. Функция — это именованный блок инструкций, который может запускаться из нескольких мест и затем возвращать управление, так что логика пишется один раз и используется где угодно. Для вызова функции нужны две вещи. Программа переходит туда, где находится функция, и запоминает, откуда она пришла, чтобы потом вернуться. jal делает и то и другое, а его название означает jump and link (переход и связывание).

Переход идёт к метке, обозначающей функцию. Часть со связыванием происходит до перехода. jal сохраняет адрес следующей инструкции, той, что идёт сразу после вызова, в регистре. Функция использует этот сохранённый адрес для возврата.

По соглашению сохранённый адрес помещается в регистр с именем ra, от return address (адрес возврата). Строка ниже выполняет переход к функции square и оставляет в ra адрес, по которому нужно вернуться.

jal ra, square

Когда функция завершается, она возвращает управление, переходя по адресу в ra, что и делает инструкция ret. Обычное сокращение для того же вызова показано ниже.

call square

Руководство RISC-V говорит, что смещение перехода считается в кратных 2 байтам величинах, расширяется со знаком и прибавляется к адресу инструкции перехода. Это даёт диапазон плюс-минус 1 MiB, где MiB — это 1 048 576 байт. jal сохраняет адрес следующей инструкции, то есть pc плюс 4, в rd. Стандартное программное соглашение о вызовах использует x1 как регистр адреса возврата и x5 как альтернативный регистр связи. Инструкции безусловного перехода используют адресацию относительно pc, что поддерживает позиционно-независимый код, то есть код, работающий там, куда он загружен в память.

jal перезаписывает ra новым адресом возврата. Если функция вызывает другую функцию, внутренний вызов заменяет сохранённый адрес внешнего. Функция, которая сама выполняет вызовы, должна сначала сохранить ra и восстановить его перед возвратом. Пример вызывает square и оставляет адрес возврата в ra.

Пример

jal ra, square   # call square; ra holds the return address