Skip to content

Arm64呼び出し規約

最初の戻り値は R0 レジスタで返す。複数ある場合は調べていない。

スタックポインタ(SP)のアドレスは RSP として参照できる。実際は R31 レジスタなのだけど、これは命令によって ZR (ゼロレジスタ)と SP (スタックポインタ)のどちらかの意味に解釈される。

Armv8では R13 レジスタで固定。

関数からの戻り先アドレスは R30 レジスタに入っている。リンクレジスタ(LR)と呼ばれる。関数呼び出しがネストしている場合は、スタックに退避しろとドキュメントに書いてある。

Armv8では R14 レジスタ。

実際のコードでは次のようにレイアウトしている。MOV 命令の .W.P フラグはArm用Goアセンブリのサフィックスに書いた。

// [元のFP(R29)][元のLR(R30)]
// ^R29 ^RSP
MOVD.W R30, -64(RSP) // RSP -= 64; *RSP = R30
MOVD R29, -8(RSP) // *(RSP-8) = R29
SUB $8, RSP, R29 // R29 = RSP - 8
...
MOVD -8(RSP), R29
MOVD.P 64(RSP), R30
RET

フレームポインタは R29 レジスタに入っている。

プログラムカウンタ(PC)は R15 レジスタで参照する。

https://blog.felixge.de/go-arm64-function-call-assembly/

Goアセンブリでは以下のように記述する。

TEXT ·mainf(SB),NOSPLIT,$0
CALL ·subf(SB)
TEXT ·subf(SB),NOSPLIT,$0
RET

このとき CALLBLR 命令を生成する。BLR はリンクレジスタに戻り先アドレスをセットしてからジャンプするので、RET 命令で正しい呼び出し元へ戻ることができる。