手続き呼び出しのまとめ
少し間があきましたが、こんばんは。
え、実はこの3日間くらいずっといボーッとしてたから更新なかったんだろって?
いやいや、まさかそんなことあるわけが・・・
まじめな話をしますと、ここ最近はずっとMIPSでの簡単なコードを書きながら、実際に高級言語(おもにC言語)で様々な分を書いた時の、実際の実行の様子がどうなっているかを勉強していました。
そんな訳で、ブログ書くにしても何載せようかちょっと迷っちゃってたんですよね・・・
今日載せるのは、手続き(関数)呼び出し時の一連の動作についてです。
MIPSにおいて、手続き呼び出し時の動作は以下の通り。
呼び出し側での処理(call時)
- 呼び出し側における一時レジスタ($a0-$a3, $t0-$t9)をスタックに退避
- 呼び出し先での引数を$a0-$a3にセット
- (引数が5つ以上ある場合は、スタックへ積む)
- jal命令でサブルーチンへ分岐
サブルーチン側での処理
(サブルーチンの主な手続き部分)
呼び出し側での処理(return時)
- call時と逆の手順でスタックから$a0-$a3, $t0-$t9を復帰
こんな感じですね。
コードでまとめると、例えば以下のような感じになります。
main: #part of execution... #part of call sub routine addi $sp, $sp, -16 #shelter of $a0-$a3 sw $a0, 12($sp) sw $a1, 8($sp) sw $a2, 4($sp) sw $a3, 0($sp) addi $sp, $sp, -40 #shelter of $t0-$t9 sw $t0, 36($sp) sw $t1, 32($sp) sw $t2, 28($sp) sw $t3, 24($sp) sw $t4, 20($sp) sw $t5, 16($sp) sw $t6, 12($sp) sw $t7, 8($sp) sw $t8, 4($sp) sw $t9, 0($sp) move $a0, $t0 #set of arguments move $a1, $t1 move $a2, $t2 move $a3, $t3 addi $sp, $sp, -16 #shelter of arguments sw $t4, 12($sp) sw $t5, 8($sp) sw $t6, 4($sp) sw $t7, 0($sp) jal subr addi $sp, $sp, 16 #restore of $sp lw $t9, 0($sp) #restore of $t0-$t9 lw $t8, 4($sp) lw $t7, 8($sp) lw $t6, 12($sp) lw $t5, 16($sp) lw $t4, 20($sp) lw $t3, 24($sp) lw $t2, 28($sp) lw $t1, 32($sp) lw $t0, 36($sp) addi $sp, $sp, 40 lw $a3, 12($sp) #restore of $a0-$a3 lw $a2, 8($sp) lw $a1, 4($sp) lw $a0, 0($sp) addi $sp, $sp, 16 #continue main execution... jr $ra #end of main subr: addi $sp, $sp, -8 #shelter of $fp and $ra sw $fp, 4($sp) sw $ra, 0($sp) move $fp, $sp #$fp = $sp addi $sp, $sp, -20 #secure area of local variale and $s0-$s7 # sw $s0, 0($sp) #(shelter of save registers) #part of execution of subr... # lw $s0, 0($sp) #(restore of save registers) move $sp, $fp #restore of $ra and $fp lw $ra, 0($sp) sw $fp, 4($sp) addi $sp, $sp, 8 jr $ra #return of subr
では今日はこの辺で!