【アセンブリ】システムコールsyscallの使い方【MIPS】
システムコール(syscall)ってなに
SPIMでオペレーティングシステム的なサービスを実行するための命令。
syscallを使う手順
サービスの要求の流れ
- レジスタ
$v0
に使いたいサービスのシステムコールコードを格納 - 引数をレジスタ
$a0
から$a3
(浮動小数点数の値は$f12
)にロード - 値を返すシステムコールは結果をレジスタ
$v0
(浮動小数点数の値の場合は$f0
)に収める syscall
で実行!
*システムコールコードはP.781を参照
やってみる
Patterson&Hennessyにあるサンプルプログラムを改変しながら読み解いてみる
.data str: .asciiz "the answer = " .text li $v0, 4 # 手順1:print_stringのシステムコールコードは4 la $a0, str # 手順2:asciizで保存したプリントする文字列のアドレスを$a0に格納 syscall # 手順4:文字列をプリント(サービス実行!) li $v0, 1 # 手順1:print_intのシステムコールコードは1 li $a0, 5 # 手順2:プリントする整数5を$a0に格納 syscall # 手順4:整数をプリント
これで単純に実行したら
Instruction references undefined symbol at 0x00400014
ってエラーが出た。ステップ実行で確認してみる。
どうやらjalでmainがないよって言われてる。jalなんてこのプログラム内にはないけど。
これはアセンブリファイルの内容に依らず呼ばれるものなのかもしれない。ということでmainを追加して動くプログラムにしようと試みる。
.data str: .asciiz "the answer = " .text main: # ここを追加 li $v0, 4 # 手順1:print_stringのシステムコールコードは4 la $a0, str # 手順2:asciizで保存したプリントする文字列のアドレスを$a0に格納 syscall # 手順4:文字列をプリント(サービス実行!) li $v0, 1 # 手順1:print_intのシステムコールコードは1 li $a0, 5 # 手順2:プリントする整数5を$a0に格納 syscall # 手順4:整数をプリント
これでなんとか動いた。でも文字が出力された後に以下のエラーが出てる…。
Attempt to execute non-instruction at 0x0040003c
なんなんだ。
必殺ステップ実行。
なんか抜け出す的なそういう処理が最後に必要なのかなとか思い勘で下記のように最後の行にj $ra
を追加
.data str: .asciiz "the answer = " .text main: li $v0, 4 # 手順1:print_stringのシステムコールコードは4 la $a0, str # 手順2:asciizで保存したプリントする文字列のアドレスを$a0に格納 syscall # 手順4:文字列をプリント(サービス実行!) li $v0, 1 # 手順1:print_intのシステムコールコードは1 li $a0, 5 # 手順2:プリントする整数5を$a0に格納 syscall # 手順4:整数をプリント j $ra # ここを追加
するとエラーなく通るようになった!!!やった!!!!
どうやら、main関数(サブルーチン、手続きともいう)から元に復帰する必要があるのでj $ra
で$ra
の値を返してやってmainを抜け出す必要があるらしい。
Cでもmain関数が正常に終了したらreturn 1;
とかで値を返してやらないといけないけど、これと同じようなする。
じゃあ なんで返す値がレジスタの$ra
なのか ってところが疑問になる。
調べた限り jal
命令にはでは$ra
は関数が呼ばれた時点で戻ってくるべきアドレスを自動で代入してくれる便利な機能があるらしい。
上で一度エラーでひっかかったときjal
命令が呼ばれていることを確認したけど、これはソースコードにはなかった。まとめると、、
jal main
って命令はどのプログラムでも最初に自動的に実行される- そして
jal
が呼ばれた瞬間に$ra
には戻るべきアドレス(返すべき値)が自動的に代入される。
みたいなことらしい。よって、$ra
はうかつに自分でいじっちゃいけないよう。
ということで
アセンブラ深い。低レイヤだからって学ぶのが簡単ってわけはなく、高いレイヤになるほどそのシステムの複雑さはうまく抽象化されてラッピングされてるんだなぁとアセンブラの勉強を進めるたびに思う。。。
githubリポジトリはこちら。今回使用したプログラムはex-syscall.sです。
GitHub - totzyuta/system-programming: [Assembly] Programs of System Programming class.
ということでprintf関数をスクラッチから実装することを目標に学習を進めます。