まず、通常 は、などの代わりに$zero
使用する必要があります。単純な数値よりも理解しやすく(そして覚えやすく)、アセンブラもこの表記を理解するため、この面で問題はありません。また、これは数値からコードを抽象化するため、標準が変更された場合(たとえば、$zeroは$0ではなく$256)、コードは正しくアセンブルされます。$0
$v0–$v1
$2–$3
すべてのCPUアーキテクチャには、呼び出しを行うためにレジスタを使用する方法と、関数内でレジスタを操作する方法に関するいくつかの規則があります。これは呼び出し規約と呼ばれます。ここで、MIPS呼び出し規約の簡単な説明を見ることができます。
レジスタをクリーンに保つこと、つまりプログラムの最後にレジスタの値を0にクリアすることは、一般的に良い習慣だと聞いています。だから私の最初の質問は、これがどのように/なぜ必要である/良い習慣であるかということです。
私は個人的にこの慣習について聞いたことがありませんが、私はそれに完全には同意しません。プログラムを開始する前に、以前の値を復元することをお勧めします。
次に、パラメーター(p1、p2)が$4と$5に格納されている関数呼び出しがある場合。関数定義の最後で、$4および$5以上の値をクリアして、関数呼び出しの開始時のままにしておく必要がありますか?
関数呼び出しの開始時のままにしておく必要があります。呼び出し元にとって、このレジスタを変更しても意味がありません。
スタック上のスペースは、呼び出し先が引数を保存する必要がある場合に備えて$ a0〜 $ a3用に予約されていますが、呼び出し元はレジスターをそこに格納しません。
このようにパラメーターをスタックにプッシュする例も見ました。いつ、なぜこれが必要/良い習慣ですか?
定義上、一時ストレージの場合はスタック。レジスタ値をバックアップする場合(たとえば、$aXまたは$sXを使用する場合)、それらをそこに配置します。以前と同じ:
呼び出し先が引数を保存する必要がある場合に備えて、スタック上のスペースは$ a0〜$a3用に予約されています
addi $sp, $sp, -8
スタックポインタレジスタを移動します(慣例により$ 29です)。これにより、スタックに8バイトが予約されます。
sw $a0, 0($sp)
sw $a1, 4($sp)
$ a0をスタックの一番上に保存し、$ a1をスタックの2番目として保存します(スタックは低いアドレスに向かって大きくなることに注意してください)。これにより、予約済みスペース(8バイト)がいっぱいになります。これは、関数入力プロトコルと呼ばれます。
; At the end of our program:
; You forgot, and it's important:
lw $a0, 0($sp)
lw $a1, 4($sp)
addi $sp, $sp, 8
保存したレジスタを復元し、スタックポインタを元の値に戻します。その後、呼び出し元はスタックとパラメーターに変更を加えません。そして、これは関数出口プロトコルと呼ばれます。
プログラムでいくつかの定数、たとえば4と1を使用する場合、それらをレジスタまたはスタックに保持する方がよいでしょうか。
ない。定数は、イミディエートオペランドとして使用する必要があります。
li $t0, C ; Load 16-bit constant into $t0
lui $t0, C ; Load upper 16-bit half-word of $t0