newbieからバイナリアンへ

コンピュータ初心者からバイナリアンを目指す大学生日記

【HelloWorld part.5】割り込み処理の引数渡し

 

 

参考書籍】ハロー“Hello, World” OSと標準ライブラリのシゴトとしくみ 坂井弘亮

 

 

0.そういえば

VDSOを無効にしたことでINT $0x80が実行されるのが

_dl_sysinfo_Int80の内部に変わったのだが

本では依然として__kernel_vsyscalの内部のままだ

VDSOを一旦有効にすべきか迷ったが

不都合が出るまではこのまま進めていくことにする

 

f:id:smallkirby:20190219214445p:plain

それと同時にINT $0x80のアドレスも大きく変わっている

 

 

 

1.割り込み処理番号を渡す

前回までで割り込み処理の入り口であろうところは見当がたった

アプリケーションからLinuxへの割り込み処理の委任がされる際に

”どの割り込み処理をするか”と”その割り込み処理に必要なデータ”の

2種類のパラメタが渡されるはずである。

まずはどの割り込み処理をするか、つまり割り込み処理番号の渡し方を調べる

 

GDBでINT命令の直前のレジスタ情報を見て見ると・・・

 

f:id:smallkirby:20190219214602p:plain

INT直前のレジスタ情報(1)

f:id:smallkirby:20190219214625p:plain

INT直前のレジスタ情報(2)

ここで注目すべきは以下のレジスタ

eax = 0x04:

これをインデックスとすると前回言及したkernel/syscall_table_32.S内sys_call_tableでのsys_write関数を指している

ecx = 0xb771a00:

(gdb) x/s *0xb771a00を調べて見ると出力メッセージが保存されていた

edx = 0x14:

出力メッセージはNULLも含めて20文字のため、文字数を保存している

ということがわかる

 

INT命令を実行した後のレジスタを見て見ると・・・

 

f:id:smallkirby:20190219215334p:plain

INT実行直後のレジスタ情報(1)

f:id:smallkirby:20190219215359p:plain

INT実行直後のレジスタ情報(2)

おおよそ直前と同じだが

当然PCであるEIPの値が変わり

それからprintf()は返り値が出力文字数であるためにEAXにEDXの値がコピーされている

 

 

とりあえずシステムコールを呼び出す直前に

コール番号はEAXで通知

他のアーギュメントはそれぞれ対応するレジスタに保存

されていることがわかった

 

 

 

2.引数の渡し方と”あまり深入りしないようにしよう”

アプリケーション側のコール直前に値がレジスタに入っていることはわかったが

x86の引数渡しはスタック渡しであるために

どこかしらのタイミングで値をスタックに積んでいるはずである

そう思ってentry_32.Sを見て見ると・・・

 

f:id:smallkirby:20190219220230p:plain

entry_32.S - SAVE_ALLマクロ

 

ここで各種レジスタ(特に上で注目したレジスタ)がpushされている

見慣れないPUSH_GSマクロを調べて見ると・・・

 

f:id:smallkirby:20190219220410p:plain

entry_32.S - PUSH_GS

 

さらにその内部にあるCFI_ADJUST_CFA_OFFSET定数を調べてみると・・・

 

f:id:smallkirby:20190219220504p:plain

entry_32.S内部にはCFI_ADJUST_CFA_OFFSETの定義は見つからない

 

よってLinuxソースのx86アーキテクチャディレクトリ内部を検索すると・・・

 

f:id:smallkirby:20190219220641p:plain

CFI_ADJUST_CFA_OFFSETを探す

どうやらinclude/asm/dwarf2.hというヘッダファイル内にあるようだ

該当ファイルを見て見ると・・・

 

f:id:smallkirby:20190219220738p:plain

CFI_ADJUST_CFA_OFFSETの定義部(1)

 

f:id:smallkirby:20190219220808p:plain

CFI_ADJUST_CFA_OFFSETの定義部(2)

 

画像のように2種類の定義部があった

おそらくCFI(が何かはわからないが)を有効にするかどうかで

分岐させているのだろう

有効部を見てみると今度は.cfi_adjust_cfa_offsetというワードがある

 

ここまで調べた段階でなんだか深みにはまっている気がして中断した

もともと筆者も行っているように

ソースを読む際には肝心な部分だけに絞って注目する必要がある

そうじゃなきゃ依存関係バリバリな複雑なコードを読み進めることなどできない

よってここでは

あまり関係なさそうなマクロや定数の定義部までは遡らず

必要に応じて名前から推測したりするなどして読み流していくこととする

 

 

 

 

とりあえず簡単に調べられそうなアセンブラの命令CLDは以下の通り

f:id:smallkirby:20190219222253p:plain

http://softwaretechnique.jp/OS_Development/Tips/IA32_Instructions/CLD.html

EFLAGSの中のDFを0にセットするようだ

その間は文字列操作時にESI/EDIがインクリメントされるようだが

これが何を意味するかは現段階ではわからない

 

 

 

まあなにはともあれ

この全てのレジスタを保存するアセンブラのマクロによって

レジスタに入れられたシステムコールの引数がスタックに積まれることがわかった

 

 

なおこれはLinux/x86の仕様であって

筆者愛用のFreeBSDでは違う仕様らしい

 

ところでFreeBSDってLinuxの一種かと思ってたけど違うっぽい?

今度Linux系OSの系譜を説明した本でも買って読みたいものだ

 

 

 

 

 

 

 

続く