スレッドメモ
MLやNewsのスレッドをメモする試み。
2004-05-14 (金)
◆ [fj][fj.os.linux] [Q] source code of connect system call
<86ad0bz0id.wl@soro1.cc.hokudai.ac.jp> Hiroki Kashiwazaki (5/14)
ネットワークプログラミングをして遊んでいる今日このごろなのですが、 connect のソースを読んでみたいなーとか考えて、libcのソースを get してきました (glibc_2.2.5.orig.tar.gz)。が、展開して探してみても connectがどこにあるのか探し当てる事は出来ませんでした。connectは system callだから、カーネルなのかしらんと、カーネルソースを取得 してきたのですが、これまた探し当てる事が出来ませんでした。
<3989746news.pl@insigna.ie.u-ryukyu.ac.jp> Shinji KONO (5/15)
それを見たいんだったら、gdb で、一回connect を呼び出してから、 x/20i connect で disassemeble するのが簡単です。何故一回呼び出すか というと、dynamic link されているから...
で、
0x400ff2f0 <__libc_connect>: mov %ebx,%edx 0x400ff2f2 <__libc_connect+2>: mov $0x66,%eax 0x400ff2f7 <__libc_connect+7>: mov $0x3,%ebx 0x400ff2fc <__libc_connect+12>: lea 0x4(%esp,1),%ecx 0x400ff300 <__libc_connect+16>: int $0x80 0x400ff302 <__libc_connect+18>: mov %edx,%ebx 0x400ff304 <__libc_connect+20>: cmp $0xffffff83,%eax 0x400ff307 <__libc_connect+23>: jae 0x400ff30a <__libc_connect+26>みたいなのが見れるので... 0x66 = 102 がシステムコール番号 だってのがわかります。
> #アセンブラソースも grep しました?>>柏崎さん
これもかなり正解に近いんですが、cpp を通るので、.s でなくて、.S だったりします。Linux には、システムコールの番号は、libc と entry.S に分離して記述されているんです。BSDだと、このあたりは config がやるんですが...
linux-2.6.5/arch/i386/kernel/entry.S
で、そこを見ても connect というのはなくて... 102 という番号を頼りに、
.long sys_fstatfs /* 100 */ .long sys_ioperm .long sys_socketcall .long sys_syslogとかいうのがあるので、sys_socketcall だってのがわかるわけですね。
でも、それでも、行きつけない。何故なら、
err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, sock->file->f_flags);となっていて、実は、indirect call だから。そりゃそうなんで、connect といっても、TCPとは限らない。decnet (ふる〜) かも知れないし。
ってのがあるから、
In /Users/kono/src/linux/linux-2.6.5/net/ipv4/tcp_ipv4.c 753:/* This will initiate an outgoing connection. */ 754:int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) 755:{ 756: struct inet_opt *inet = inet_sk(sk);だってのがわかりますね。
<86ekphxceq.wl@soro1.cc.hokudai.ac.jp> Hiroki Kashiwazaki (5/19)
ようやくクリアになりつつありますが、もう何点か。 理解のための僕の思考過程をまとめると、以下のようになります。
- connect を使うのに <sys/socket.h> を include する。
- <sys/socket.h> には extern int connect ... の宣言がある。
- コンパイルする時に libc とリンクが行われる
- libc で connect は アセンブラでコーディングされているので、connectのCのソースを探そうとしても見つからない。
- connectのアセンブラソースには
> レジスタ EAX に 0x66 を、EBX に 3 を、ECX には呼び出し元から
> 渡されたディスクリプタをセットして、割り込み 0x80 を発生させる
というコードが書かれてある。 [でもこれはどこにある ?]
- arch/i386/kernel/entry.S に記述されているように呼び出す関数から EAX==0x66に対応する sys_socketcall を得る。sys_socketcall に与える引数 には EBX==3 が定められる。
↓
- sys_socketcall ( EBX==3==SYS_CONNECT , hogehoge ) を呼び出す
↓
- sys_connect を呼び出す
↓
- socket file descriptorに適切な関数を呼び出す