Re: [Q] source code of connect system call
いいじまです。
> まだあやふやなのですが、書かれたソースから、それが実現されるまでの
> 流れとしては
>
> ・ソースに記述された connect 関数
> ↓
> ・コンパイル時にシステムコールとして認識され、
> arch/i386/kernel/entry.S に記述されているように呼び出す関数
> (sys_socketcall) を得る ? そのときに sys_socketcall に与える
> 引数 (SYS_CONNECT) はどこから得られる ?
> ↓
> ・sys_socketcall ( SYS_CONNECT, hogehoge ) を呼び出す
> ↓
> ・sys_connect を呼び出す
> ↓
> ・socket file descriptorに適切な関数を呼び出す
>
> という理解で良いのでしょうか。ここらへんがあやふやでどうにも。
えっと、ちょっと違います。
河野さんの説明してくれた手順を再度追ってみましょう。
まず、C の関数としての connect() は、「普通の libc の関数」です。
C 言語で connect() を呼び出す適当なコード(動かなくても文法的に正しけれ
ばよい)を書いて、gcc -O6 --fomit-frame-pointer -S というオプションでア
センブラソースを吐き出させて、読んでみてください。全く同じように、printf()
を呼び出すコードも書いて、同じようにアセンブラソースを書いて、読み比べて
みてください。ほぼ同じコードだということがわかると思います。つまり、コン
パイラはこの部分については全く関知しません。
ところがこの connect() はアセンブラで書かれていて、
レジスタ EAX に 0x66 を、EBX に 3 を、ECX には呼び出し元から
渡されたディスクリプタをセットして、割り込み 0x80 を発生させる
というコードが書かれています。この「EAX=0x66」「EBX=3」「割り込み 0x80」
というのは、カーネルが好き勝手に決めている数値で、他のシステムコールと重
複卯していなければ特にこの数値でなくてもかまいません。
この割り込み発生で、制御がカーネルに渡ります。
制御を受け取ったカーネルは、entry.S に書いてある関数ポインタ配列から、
EAX==0x66 に対応する関数を探し出します。これが、sys_socketcall です。
で、
> switch(call)
> {
> case SYS_SOCKET:
> err = sys_socket(a0,a1,a[2]);
> break;
> case SYS_BIND:
> err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);
> break;
> case SYS_CONNECT:
> err = sys_connect(a0, (struct sockaddr __user *)a1, a[2])
> ;
> break;
というコードにたどりつくわけですが、おそらく SYS_CONNECT が、割り込みを
発生させるときに使った EBX=3 という値に対応しているのでしょう。で、EBX
に 3 以外の値をセットすると、同じ int 0x80、EAX=0x66 が socket() の呼び
出しになったり、bind() の呼び出しになったりする、と。(すいません、実際
のコードは追っていないので憶測です。)
で、そのあと呼び出される関数は、最初に socket() でソケットを生成したとき
に、ソケットの種類に応じて、ディスクリプタテーブル上の関数ポインタには、
○○の処理を行う関数はどれ、○○の処理を行う関数は○○、という値が設定さ
れていますので、それを参照して呼び出しを行うと、最終的に tcp_v4_connect()
にたどりつく、というわけです。
P.S.
このへんのアセンブラの初歩って、昔は MS-DOS で int86x() なんかをよく使っ
たものですが、今は何を使って勉強するのが素直なんだろう…
========================================================================
飯嶋 浩光 / でるもんた・いいじま http://www.ht.sakura.ne.jp/~delmonta/
IIJIMA Hiromitsu, aka Delmonta mailto:delmonta@ht.sakura.ne.jp
Fnews-brouse 1.9(20180406) -- by Mizuno, MWE <mwe@ccsf.jp>
GnuPG Key ID = ECC8A735
GnuPG Key fingerprint = 9BE6 B9E9 55A5 A499 CD51 946E 9BDC 7870 ECC8 A735