level4

新しいシステムコールを提案し、実装してみよ。
まず、printfを使用してメッセー ジを表示するだけのシステムコールを作成する。

kernelのconfigの過程で、使用するシステムコールの番号等を指定するファイル がある。これを使うと、
  1. アプリケーションが呼び出すライブラリ(libc)
  2. ライブラリが呼び出すtrap
  3. trapを受け取り振り分ける部分
  4. 実際にkernel内部で処理する部分
のうち、3番目は、自動的に生成される。

もちろん、テストするアプリケーションも必要である。

アプリケーションからは、trapをアセンブラで直接起動しても良いし、libcを修 正して、
普通のCの関数に見えるようにしても良い。
system call追加方法

1: linux/include/asm(-i386)/unistd.h の修正

#define __NR_exit                 1
#define __NR_fork                 2
...

となっているところがあるので、それの末尾に

#define __NR_(システムコール名) (空き番号)

を挿入。この時の空き番号がシステムコール番号になるので憶えておくこと。


2: linux/arch/i386/kernel/entry.S の修正

.data
ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_call)           /* 0 */
.long SYMBOL_NAME(sys_exit)
.long SYMBOL_NAME(sys_fork)
...

次のようなテーブルがあるので、既にあるシステムコールのコメントを元に
先程のシステムコール番号と一致する場所に

.long SYMBOL_NAME(sys_(システムコール名))

を挿入。
また、Linux2.6.XXの場合、entry.Sにはシステムテーブルに関するテーブルが無 く、
その代わりに linux/arch/i386/kernel/syscall_teble.S にそれに近いことが記 述されているので
システムコール番号と一致する場所に

.long sys_(システムコール名)

を挿入することで設定出来る。


3: linux/arch/i386/kernel/Makefile の修正

obj-y   := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o\
                ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
                pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o

のようになっている箇所があるのでここに (システムコール名).o を追記。


4:ヘッダファイルの作成

"(システムコール名).h"というファイルを次の書式で linux/include/linux ディ レクトリに記述。

#ifndef __LINUX_(システムコール名を大文字で)_H
#define __LINUX_(システムコール名を大文字で)_H

#include 
#include 
#include 

(※)

#endif

※ここには_syscallX(Xはシステムコールのとる引数の数が入る、0の場合は省略) という関数が入る。
例えばX=2の場合の書式はこうなる。

_syscall2((システムコールの関数型),(システムコールの名前),(引数1の変数 型),(引数1の名前),(引数2の変数型),(引数2の名前));

これは、システムコールを呼び出すための関数(=ライブラリ関数)を作るための マクロである。


5:システムコール本体の作成

"(システムコール名).c"というファイルを次の書式で linux/arch/i386/kernel ディレクトリに記述。

#include 

asmlinkage (関数型) sys_(システムコール名)(引数) {
/*システムコール実行部*/
}

ここまで完了したらカーネルを再構築することで追加したシステムコールが使用 可能になる。

ちなみに今回の実験で使用するシステムコールとそれの検証用のプログラムは以 下の通り。

#与えられたint数値の三倍の値を返すシステムコール sys_arg_triple()

○arg_triple.h
#ifndef __LINUX_ARG_TRIPLE_H
#define __LINUX_ARG_TRIPLE_H

#include 
#include 

_syscall1(int, arg_triple, int, arg1);

#endif

○arg_triple.c
#include 

asmlinkage int sys_arg_triple(int arg1) {
  int j = 3;
  j = j * arg1;
  return j;
}

○syscalltest.c
#include 
#include 
#include  

int main() {
   int i = 3;
   printf("test arg_triple(%d) = %d ?n", i, arg_triple(i));
   return 0;
}

システムコールをテストするプログラムには必ずシステムコールのヘッダファイ ルを include させること。


syscalltest.c実行結果

[j03063@pw039 ~/info4]% ls
syscalltest.c
[j03063@pw039 ~/info4]% gcc -o test.out syscalltest.c 
[j03063@pw039 ~/info4]% ./test.out 
Incorrectly built binary which accesses errno or h_errno directly. Needs
to be fixed.
test arg_triple(3) = 9 
[j03063@pw039 ~/info4]% 

設定や書式が悪かったのか、エラーが発生している。
時間が無かったので原因究明はしていない。
ただ、システムコール自体は正常に動いている模様。


考察

今回の実験は単純なプログラムを組むだけだったので難易度は低めだったものの、
カーネルの内部をいろいろと見て回らないといけなかったため、 時間がかかってしまった。
そして、今回の実験でLinuxカーネルというものが多くのプログラムの集合体で あり、
それを修正するのもカーネルに機能を追加するのもそれなりの技量があれば可能 だということがよくわかった。

参考リンク

http://www.google.com/search?q=cache:HA-z_nCa8SIJ:www.csg.is.titech.ac.jp/~chikayasu/syscall.html

linux/include/asm(-i386)/unistd.h の修正
linux/arch/i386/kernel/entry.S の修正
linux/arch/i386/kernel/Makefile の修正
ヘッダファイルの作成
システムコール本体の作成
実行結果
考察
参考リンク

level3 top level5