システムコールとは - 2024年度 システムプログラミング
システムコールとは
はじめに
これまで,出力装置に 'A' を出すプログラムでは,
0xffff000c
番地に直接 65
を書込むことで実現してきました.
ここでは,オペレーティングシステム (OS) を意識した出力方法を学びます.
野蛮な文字出力
以下は,出力装置に 'A' を出すプログラムでした.
.text .align 2 putc: lw $t0, 0xffff0008 # 0xffff0008の中身を$t0に li $t1, 1 # $t1 = 1 and $t0, $t0, $t1 # $t0 = $t0 & $t1 beqz $t0, putc # if ($t0 == 0) goto putc sw $a0, 0xffff000c # 0xffff000c に$a0を書込 j $ra #
しかし,実は,これは,かなり野蛮な方法です.なぜなら:
0xffff000c
(計算機毎に変わり得るアドレス)を プログラマが意識して使うのは面倒.アドレスを知る術がないこともある.- 他のプログラムと同時に走行した場合,競合が発生する.
- 印刷可能になるまで待つ事をしないプログラムを誤って作成した場合,機器が壊れる可能性がある.
そのため,入出力装置に対応するメモリを一般のプログラムでは, 直接読み書きできないのが普通 (UNIX や Windows も)です.
行儀よくプリンタを使うには?
通常のOSでは,これらの問題をカーネルと呼ばれる専用のサブルーチン集を用意して, 全てのプログラムがそのサブルーチンを呼出すことで解決しています. カーネルを用意するメリットは,以下の通りです.
- 呼出し方を決めておけば,プリンタのアドレスが変化しても, (プリンタの出力方式が変わっても)プログラムを変更する必要がない.
- 他のプログラムとの競合を調整してもらえる.
このサブルーチンの事をシステムコールといいます.
システムコールは, カーネル(OS) 毎に引数の意味, つまり,どのレジスタにどういう意味を持たせるか異なります. 以下は,本演習で使用するSPIMがあらかじめ持っているシステムコールの一覧から, 本演習で使用する部分の抜粋です. (教科書A.9節「SPIM」の「システム・コール」より)
サービス | No | 引数 | 戻値 |
---|---|---|---|
print_int | 1 | $a0 = integer | |
print_string | 4 | $a0 = string | |
read_int | 5 | $v0 | |
read_string | 8 | $a0 = buffer, $a1 = length |
以下は,システムコールを使った,プログラムの例です.
.text .align 2 main: li $v0, 1 # No = 1 (print_int) li $a0, 5 # 5 を表示 '5' ではない syscall # 画面に '5' と出る j $ra
ここで, syscall
命令を使っていますが,
なぜこれまでのサブルーチンのように jal
を使わないのでしょうか.
syscall
命令が必要な理由は何でしょうか.主な理由は,以下の通りです.
- サブルーチンのアドレスは,カーネルがバージョンアップする毎に 変化するので(例: Windows7 → Windows8),結局, プリンタのアドレスを知るのと同じ問題が発生する.
- カーネルのとんでもないアドレスに
jal
してもらっては困る. つまり,番地を指定して任意のアドレスから実行できるとカーネルを悪用できる.
これらの理由から,カーネルの中にある手続き(関数)へは, 直接ジャンプできないように,メモリが保護されています.
まとめると,以下の2つがシステムの安全性を保証しています.
- プリンタを操作するアドレス (
0xffff000c
等) は, カーネル中のプログラムからしかアクセスできない. - カーネル中の任意のプログラム部分に外部からはジャンプできない.
これを実現するための仕組みである「走行モード」 と
syscall
について理解しましょう.
走行モードの切り替え
システムの安全を保証するためには,以下の保護が必要であることが分かりました.
- カーネルのプログラムが走行しているときだけ, 特権を持ったモード(全メモリを自由に操作できる)になる必要がある.
- 誰にでも簡単に特権モードになられては困る.
- カーネルの内のアドレスに外部から
jal
してもらっても困る. そうでないと,- 番地を指定して,任意のアドレスから実行できる.
- その結果,カーネルを悪用できる.
この問題を解決するのが, syscall
命令です.
- syscall 命令
- ユーザプログラムの権限から特権モードに移行する代わりに, カーネルが設定した特定のアドレスにしかジャンプできない命令.
syscall 命令を使用したプログラムの動作を以下に示します.
- ユーザプログラムでレジスタに引数を入れて
syscall
命令を実行 syscall
によって,カーネルが設定したアドレスにジャンプsyscall
実行と同時に,自動的に特権モードになる- カーネル内で引数の厳重なチェック
- ユーザプログラムの望む処理をカーネルが代わりに実行
- 通常の走行モードに移行
- ユーザプログラム(の
syscall
呼び出し直後)に戻る
この 1から3 までが, syscall
命令の動作です.
これによって,安全にユーザプログラムからカーネルやメモリ資源を保護することができ,
カーネルに所望の処理を依頼できるのです.