システムコールライブラリとは - 2024年度 システムプログラミング
システムコールライブラリとは
以下は,もう何度も見てきた出力装置に直接 'A' を出すプログラムです.
1: .text 2: .align 2 3: putc: 4: lw $t0, 0xffff0008 # 0xffff0008の中身を$t0に 5: li $t1, 1 # $t1 = 1 6: and $t0, $t0, $t1 # $t0 = $t0 & $t1 7: beqz $t0, putc # if ($t0 == 0) goto putc 8: sw $a0, 0xffff000c # 0xffff000c に$a0を書込 9: j $ra #
上記は,基本的にメモリを扱うプログラムであるので, C言語のポインタを駆使して,同等の記述をすることができます. 以下がその例です.
1: void putc(int c) 2: { 3: /* (1) 最下位ビットを判定 */ 4: while ((*(volatile int*)0xffff0008U & 1) == 0) { 5: ; /* 下位1ビットが0 → 何もしないでもう一度 */ 6: } 7: /* 送信データを書込む */ 8: *((volatile int*)0xffff000cU) = c; 9: }
しかし,この方法は,かなり野蛮な方法であると,以前説明して, システムコールを用いる方法を解説しました.(参照: システムコールとは)
以下は,そのシステムコールを用いた例です.
1: .text 2: .align 2 3: main: 4: li $v0, 1 # No = 1 (print_int) 5: li $a0, 5 # 5 を表示 '5' ではない 6: syscall # 画面に '5' と出る 7: j $ra
システムコールのために syscall
命令を用いる必要があります.
C言語でも syscall
命令を使えれば,野蛮な方法を使わないで済みます.
しかし,Cで直接 syscall
命令を記述する方法がありません.
そこで, syscall
を用いなければならない部分のみをアセンブラで記述し,
C言語からは,その部分をC言語の関数として呼び出したいというのが,
今回の目的です.例えば,
print_int
という名前でC言語から呼び出すことができる関数をアセンブラで用意するということです.
そのアセンブラ中で syscall
を使います.
これによって,C言語から入出力を行える上に, 入出力以外の部分をC言語で記述することで, 全体の開発効率が大きく改善するはずです.
例えば,C言語から print_int(int i)
を呼出せるように,
syscalls.s
の中で _print_int
を記述しておきます.以下の通り.
1: .text 2: .align 2 3: 4: /* void print(int i) */ 5: _print_int: 6: subu $sp,$sp,24 7: sw $ra,20($sp) 8: 9: li $v0, 1 # No = 1 (print_int) 10: syscall 11: 12: lw $ra,20($sp) 13: addu $sp,$sp,24 14: j $ra
これは,以前勉強した手続き呼び出し規約にマッチしています.
- スタックフレームを 24バイト以上確保している.
syscall
中で$ra
が壊れる場合を考えて,$ra
を保存している.- 保存が要求されるレジスタを壊していない.
- C言語から渡される 1番目の引数は
$a0
であることを利用して,syscall
にそのまま渡している.
ただし, syscall
中での処理が引数と戻り値に使用するレジスタ以外を壊さないという前提に基づいています.
また,以下の点に注意して下さい.
- C言語から
funcname
を呼出すときは,アセンブラでは_funcname:
として記述する.
これは,本実験に用いる gcc のルールで,コンパイラに依存します.
print_int
には戻り値がありませんが,Cの呼出し元に戻り値を返す必要がある場合は,
規約にのっとって, $v0
に戻り値を設定することに気をつけてください.