プロセス1実行編③(ユーザーモード) initcode.S (Xv6を読む~OSコードリーディング~)
前回
jupiteroak.hatenablog.com
トップページ
jupiteroak.hatenablog.com
initcode.S
https://github.com/mit-pdos/xv6-public/blob/master/initcode.S
# Initial process execs /init. # This code runs in user space. #include "syscall.h" #include "traps.h" # exec(init, argv) .globl start start: pushl $argv pushl $init pushl $0 // where caller pc would be movl $SYS_exec, %eax int $T_SYSCALL # for(;;) exit(); exit: movl $SYS_exit, %eax int $T_SYSCALL jmp exit # char init[] = "/init\0"; init: .string "/init\0" # char *argv[] = { init, 0 }; .p2align 2 argv: .long init .long 0
initcode.Sは、ユーザモードのプロセス1として最も初期に実行されます。
initcode.Sでは、execシステムコールを呼び出して、init.cファイルを実行しています。
処理の内容
exitシステムコールを呼び出す
.globl start start: pushl $argv pushl $init pushl $0 // where caller pc would be movl $SYS_exec, %eax int $T_SYSCALL
# char init[] = "/init\0"; init: .string "/init\0" # char *argv[] = { init, 0 }; .p2align 2 argv: .long init .long 0
.globl start
.globl(globlディレクティブ)を使って、startラベルを外部のファイルから参照できるようにします。
start:
pishl命令が配置されているアドレスにstartラベル(シンボル名、名前)を付けます。
pushl $argv
push命令によって、argvラベルが付けられたアドレス = execシステムコールの第二引数の値 = コマンドライン引数配列の先頭アドレス をスタックに退避させます。
argvラベルが付けられたアドレスには、コマンドライン引数配列が配置されています。1つ目の要素はinitラベルのアドレス値(.long init)、2つ目は0の値(.long 0、配列の終わりを意味する値)です。
pushl $init
push命令によって、initラベルが付けられたアドレス = execシステムコールの第一引数の値 = ファイルパスとなるNULL終端文字列の先頭アドレス をスタックに退避させます。
initラベルが付けられたアドレスには、ファイルパスとなるNULL終端文字列のデータ( .string "/init\0")があります。
今回のexecシステムコールでは、initというファイルをロードして実行します。
pushl $0
push命令によって、リターンアドレスをスタックに退避させる挙動を再現しています。
高級言語による記述でシステムコールを呼び出す場合は、システムコールの引数とリターンアドレス(プログラムカウンタ eipレジスタの値)がスタックに退避されます。
今回は、アセンブリ言語で直接システムコールを呼び出す手続きを記述しているので、システムコールの呼び出し元に戻るために必要なリターンアドレスが存在しません。ここでは、リターンアドレスに相当する値を0としてスタックに退避させています。
movl $SYS_exec, %eax
movl命令によって、execのシステムコール番号7(SYS_exec)をeaxレジスタにセットします。
システムコールを利用する場合は、そのシステムコールに対応するシステムコール番号(システムコールを識別する番号)をeaxレジスタにセットする必要があります。execシステムコールに対応するシステムコール番号は7(SYS_exec)なので、この値をeaxレジスタにセットしています。
int $T_SYSCALL
int $T_SYSCALL命令により、execsシステムコールを呼び出します。
int $T_SYSCALL命令を実行するとソフトウェア割り込みが生じ、割り込みディスクリプタテーブルにあるインデックスT_SYSCALL(0x40→64)のエントリが参照しているハンドラへ処理が移ります(Xv6では、割り込みベクタ番号0x40→64をシステムコールに割り当てています)。
execシステムコールが成功した場合、呼び出し元(initcode.S)に処理は戻りません。