Программирование на языке Assembler
Псевдо-инструкции для условного ветвления
В таблице 4.4 приведены псевдо-инструкции для условного ветвления. Первая часть из них упрощает ветвление с использованием операций сравнения с нулём без использования регистра x0. Вторая часть предлагает удобные функции для сравнения за счёт переупорядочивания параметров базовых инструкций, например, вызов команды ble rs, rt, imm эквивалентен вызову bge rt, rs, imm.
Псевдо-инструкция | Набор базовых инструкций | Описание |
---|---|---|
beqz rs, imm | beq rs, x0, imm | if (rs == 0) PC+=imm |
bnez rs, imm | bne rs, x0, imm | if (rs != 0) PC+=imm |
blez rs, imm | bge x0, rs, imm | if (rs <= 0) PC+=imm |
bgez rs, imm | bge rs, x0, imm | if (rs >= 0) PC+=imm |
bltz rs, imm | blt rs, x0, imm | if (rs < 0) PC+=imm |
bgtz rs, imm | blt x0, rs, imm | if (rs > 0) PC+=imm |
bgt rs, rt, imm | blt rt, rs, imm | if (rs > rt) PC+=imm |
ble rs, rt, imm | bge rt, rs, imm | if (rs <= rt) PC+=imm |
bgtu rs, rt, imm | bltu rt, rs, imm | if (rs > rt) PC+=imm, unsign. |
bleu rs, rt, imm | bgeu rt, rs, imm | if (rs <= rt) PC+=imm, unsign. |
Псевдо-инструкции для безусловного перехода
Наконец, псевдо-инструкции для безусловного перехода упрощают программирование за счёт того, что в их составе не нужно указывать имена регистров. А переход на дальние адреса реализуется командами call и tail.
Псевдо-инструкция | Набор базовых инструкций | Описание |
---|---|---|
j imm | \jal x0, imm | PC += imm |
jal imm | jal x1, imm | x1 = PC+4; PC += imm |
jr rs | jalr x0, rs, 0 | PC = rs |
jalr rs | jalr x1, rs, 0 | x1 = PC+4; PC = rs |
ret | jalr x0, x1, 0 | PC = x1 |
call imm | auipc x6, imm[31:12] jalr x1, x6, imm[11:0] | x1 = PC+4; PC = imm |
tail imm | auipc x6, imm[31:12] jalr x0, x6, imm[11:0] | PC = imm |
Бинарный интерфейс для приложений (ABI) и пользовательский режим
До сих пор обращение к регистрам происходило по их именам. Однако, существует бинарный интерфейс для приложений (Application Binary Interface, ABI), подробнее про него можно почитать по ссылке: https://github.com/riscv-non-isa/riscv-elf-psabi-doc. Он представляет собой ряд правил, описывающих, как и какие регистры должны быть использованы для решения задач. Среди прочего, ABI предоставляет псевдонимы в том числе и для регистров.
Кроме того, одним из соглашений, регламентируемых ABI, является то, как устроен механизм сохранения значений регистров при переходе в подпрограмму: в момент вызова адрес возврата сохраняется в регистре, а программный счетчик устанавливается на начало функции. Функции состоит из инструкций, которые, собственно, и выполняются функцией; после выполнения функции управление передаётся инструкции, следующей следом за инструкцией вызова. Чтобы вернуться, функция использует сохранённый адрес возврата, а значит должно быть соглашение о том, какой из регистров используется для хранения адреса возврата в случае, если над программой работает большое число программистов. Кроме того, важно соглашение о том, какие регистры можно считать измененными или неизменяемыми при выходе из функции. В таблице ниже приведены псевдонимы и разъяснение соглашения о хранении. Например, регистр x1 имеет псевдоним ra, который обозначает адрес возврата, и вызывающая функция должна сохранить значение регистра x1 до вызова функции и восстановить его после возврата функции.
Регистр | Псевдоним ABI | Описание | Кто сохраняет значение |
---|---|---|---|
x0 | zero | Константный ноль zero constant | - |
x1 | ra | Адрес возврата return address | Вызывающий код |
x2 | sp | Указатель на стек stack pointer | Вызываемая функция |
x3 | gp | Глобальный указатель global pointer | Не должен использоваться в пользовательском режиме |
x4 | tp | Указатель потока thread pointer | Не должен использоваться в пользовательском режиме |
x5-x7 | t0-t2 | Временные значения temporaries | Вызывающий код |
x8 | s0 / fp | Сохраняемый регистр / Указатель на фрейм saved / Frame pointer | Вызываемая функция |
x9 | s1 | Сохраняемый регистр saved register | Вызываемая функция |
x10-x11 | a0-a1 | Аргументы функций / Возвращаемые значения function args. / return values | Вызывающий код |
x12-x17 | a2-a7 | Аргументы функций function arguments | Вызывающий код |
x18-x27 | s2-s11 | Сохраняемые регистры saved registers | Вызываемая функция |
x28-x31 | t3-t6 | Временные значения temporaries | Вызывающий код |
pc | - | Программный счётчик program counter | - |
Указатель на стек, глобальный указатель и указатель потока используются на системном уровне. Глобальный указатель и указатель потока не должны быть использованы никем, кроме операционной системы, а указатель на стек может быть использован для сохранения и восстановления значения.
В данном курсе мы рассматриваются только непривилегированные инструкции ISA. Архитектура RISC-V предусматривает три уровня привилегий: пользовательский (User, U), супервизора (Supervisor, S) и аппаратный (Machine, M). Системные вызовы, такие как, например, функции API операционной системы, выполняются либо уровне супервизора, либо на аппаратном уровне. Для использования функций операционной системы в пользовательском режиме необходимо выполнить системные вызовы строго придерживаясь ABI.