2.6 系の Linux カーネルのコードを解説してくれている本を読んでみたら、 最新の Linux カーネルの実装がどの程度変化しているのかちょっと調べてみたくなってしまった.

なので今回は int $0x80sysenter が呼ばれた際のシステムコールハンドラの動きをちょっとだけ比べてみた.

ちょっと見比べてみたときのメモの単なる垂れ流し. オチなし.

x86/x64 でのシステムコール呼び出し - int $0x80 と sysenter って何が違うのよ

x86 の Linux では古くは int $0x80 / iret によるソフトウェア割り込みでシステムコール呼び出しを行っていたらしいが、呼び出しのオーバーヘッドが大きいことから近年の実装では x86 では sysenter/sysexit、x64 では syscall/sysret が使われているらしい.

sysentersyscall は近年の x86 や x64 CPU で追加された命令らしい. こっちのほうが int $0x80 よりも高速に動くから、こっちを使うことにしましたって感じですかね.

v2.6.39

Linux カーネル 2.6.39 では arch/x86/kernel/entry_32.S#498 および arch/x86/kernel/entry_64.S#455 にて ENTRY(system_call) によって system_call というラベルが定義されている.

加えて、arch/x86/kernel/traps.c#871 には system_call ラベルを割り込みハンドラに登録しているようなので、system_call ラベルがシステムコール実行の窓口になっている模様.

arch/x86/kernel/entry_32.S#509 および arch/x86/kernel/entry_64.S#487 で実際にシステムコール処理関数を実行している. sys_call_table はシステムコールハンドラの一覧が登録されているテーブルの先頭を示すラベルとなっており、eax にポインタ幅 (4 バイト あるいは 8 バイト) をかけた値を sys_call_table に加えることで、eax の値を添え字にして実行するシステムコールを切り替えている.

システムコールの一覧は arch/x86/kernel/syscall_table_32.Ssys_call_table ラベル以下の定義として書かれている.

v4.18-rc5

現在の最新バージョン 4.18-rc5 では arch/x86/kernel/entry_32.Sarch/x86/kernel/entry_64.Sarch/x86/entry/entry_32.S および arch/x86/entry/entry_64.S へと移動している.

ENTRY(system_call) という記述は消えており、代わりに entry_32.S には ENTRY(entry_SYSENTER_32)#414 および ENTRY(entry_INT80_32)#532entry_64.S には ENTRY(entry_SYSCALL_64)#206 というラベルがそれぞれ定義されている. (int $0x80 は 32 bit 環境の後方互換のためにしか利用されていないのだろう)

x86 における ENTRY(entry_INT80_32) の IDT への登録は arch/x86/kernel/idt.c#104 でされている模様.

各システムコール処理関数の呼び出しは、entry_32.S では do_fast_syscall_32#456 および do_int80_syscall_32#544entry_64.S では do_syscall_64#238 で行われているっぽい.

これらの do_ 系の関数は arch/x86/entry/common.c 中にそれぞれ定義されている. (do_fast_syscall_32()#353do_int80_syscall_32#345do_syscall_64()#272)

実際のシステムコール処理関数の呼び出しは ia32_sys_call_table あるいは sys_call_table というシステムコールハンドラ一覧が登録された関数ポインタ配列を介して行っている模様. x86 では #326#334、x64 では #290 で実際に呼び出しを行っているらしい.

なお、v2.6.39 においてシステムコールハンドラの一覧が記述されていた arch/x86/kernel/syscall_table_32.S は既に消滅している. そのかわりに、arch/x86/entry/syscalls ディレクトリに syscall_32.tbl および syscall_64.tbl というシステムコール一覧が書かれたファイルが新たに作られている.

で、おそらくは同じディレクトリに存在するシェルスクリプト syscalltbl.shMakefile の雰囲気を察するに、システムコール一覧が定義されたアセンブリコードはこれらのシェルスクリプトで自動生成してるっぽい.(細かく読めてはいないが)

変数 ia32_sys_call_tablesys_call_tablearch/x86/entry/syscall_32.c#27arch/x86/entry/syscall_64.c#18 あたりで定義されているっぽい. が、この変数の定義の記述がかなり謎…

#include<asm/syscalls_32.h>#include <asm/syscalls_64.h> という記述が含まれているが、リポジトリ内にはこれらのヘッダファイルは見当たらない. 前述の arch/x86/entry/syscalls/Makefile 中の記述の雰囲気的に、これらのヘッダファイルも自動生成されると思われる.

総評

(案の定)原型ないやん.

まぁでも、わりと読もうとすれば読めそう. もう少し本で勉強してからそのうち再チャレンジしてみよう.