ret疑似

ret

疑似
RISC-V アセンブリ 参考

lyszt.netはretおよびその他のRISC-V命令をより詳しく扱っています。

説明

ret は関数から戻り、制御を呼び出し元に返します。call はそれを期待します。関数が呼び出されると、呼び出し元は戻りアドレスを ra レジスタに入れ(call と jal を参照)、ret はそのアドレスにジャンプし、元の呼び出しの直後から続行します。これは ra にジャンプする疑似命令です。

ret は ra がまだ正しいアドレスを保持している場合にのみ機能します。他に何も呼び出さない関数では、入口から出口までの間に ra を変更するものはありません。関数内の call は ra を新しい戻りアドレスで上書きし、関数が必要とするアドレスを消してしまいます。他の関数を呼び出す関数は、入口で ra を保存し、ret の前に復元します。復元しないと、関数は間違った場所に戻り、プログラムは無関係なコードにジャンプするか、永遠にループします。

慣例により、関数は戻る前に結果を a0 レジスタに入れ、呼び出し元はそこでそれを読み取ります。

RISC-V マニュアルによると、標準呼び出し規約におけるプロシージャリターンは、rd=x0、rs1=x1、即値 0 の jalr としてエンコードされます。これは x1 のアドレスにジャンプし、x0 がそれを破棄するためリンクアドレスを書き込みません。マニュアルはさらに、プロセッサが jal と jalr のレジスタ番号を関数リターンの予測のヒントとして使用すると付け加えており、これが標準規約が戻りアドレスを x1 に保持する理由の一つです。

例は最も単純な完全な関数です。square は引数にそれ自身を掛け、ret は結果を返します。他に何も呼び出さないため、何も保存も復元もしません。シミュレータで実行すると、制御が呼び出し元にジャンプして戻ることがわかります。

展開先

jalr zero, ra, 0

アセンブラはこの疑似命令を、上記に示された実際の命令または複数の命令に置き換えます。

例

square:
  mul a0, a0, a0
  ret              # return to the caller