ret
псевдоlyszt.net охоплює ret та інші інструкції RISC-V більш детально.
Опис
ret повертається з функції та передає керування назад викликачу. call очікує його. Коли функція викликається, викликач поміщає адресу повернення в регістр ra (див. call і jal), а ret виконує перехід за цією адресою, яка продовжується одразу після початкового виклику. Це псевдоінструкція, яка виконує перехід за ra.
ret працює лише тоді, коли ra все ще містить правильну адресу. У функції, яка більше нічого не викликає, ніщо не змінює ra між входом і виходом. call всередині функції перезаписує ra новою адресою повернення та стирає ту, яка потрібна функції. Функція, яка викликає інші, зберігає свій ra при вході та відновлює його перед ret. Без відновлення функція повертається не туди, і програма переходить до не пов'язаного коду або зациклюється назавжди.
За домовленістю функція поміщає свій результат у регістр a0 перед поверненням, і викликач читає його звідти.
Посібник RISC-V каже, що повернення з процедури в стандартній угоді викликів кодується як jalr з rd=x0, rs1=x1 та безпосереднім значенням 0. Він виконує перехід за адресою в x1 і не записує адресу зв'язку, оскільки x0 її відкидає. Посібник додає, що процесори використовують номери регістрів у jal і jalr як підказки для передбачення повернень з функцій, що є однією з причин, чому стандартна угода зберігає адресу повернення в x1.
Приклад — це найпростіша повна функція. square множить свій аргумент на себе, а ret повертає результат. Вона більше нічого не викликає, тому нічого не зберігає та не відновлює. Запуск її в симуляторі показує, як керування повертається до викликача.
Розгортається до
jalr zero, ra, 0
Асемблер замінює цю псевдоінструкцію реальною інструкцією або інструкціями, переліченими вище.
Приклад
square: mul a0, a0, a0 ret # return to the caller
