read()とfread()が呼ばれてからの流れ
ひょんなことからread()とfread()が呼ばれてからシステムコールにたどり着くまでを追ってみたので、メモがてらここに書いておきます。
FreeBSD 6.3-STABLE のソースをざっと追ってみたところ、
fread() からの関数コールトレース(下記参照)では__sys_read() を呼び出していました。
lib/libc/stdio/fread.c
fread() { : ret = __fread(buf, size, count, fp); : }
↓
__fread() { : __srefill(fp) : }
↓
lib/libc/stdio/refill.c
int __srefill() { : fp->_r = _sread(fp, (char *)fp->_p, fp->_bf._size); : }
↓
lib/libc/stdio/stdio.c
_sread(fp, buf, n) { : ret = (*fp->_read)(fp->_cookie, buf, n); : }
↓
lib/libc_r/uthread/uthread_read.c
_read(int fd, void *buf, size_t nbytes) { : while ((ret = __sys_read(fd, buf, nbytes)) < 0) { : }
一方、read()の入り口が見つからなかったのですが、read() が入っているであろう libc.a を
objdump -t してシンボルを見たところ、read というシンボルは read.S というファイルに存在しているようです。
/usr/obj/usr/src/lib/libc/read.S
(コンパイル時に動的に作成されるようで探し難い…)
#include "SYS.h" RSYSCALL(read)
↓
/usr/src/lib/libc/i386/SYS.h を見ると、
#define SYSCALL(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); \ ENTRY(__CONCAT(__sys_,x)); \ .weak CNAME(x); \ .set CNAME(x),CNAME(__CONCAT(__sys_,x)); \ .weak CNAME(__CONCAT(_,x)); \ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \ mov __CONCAT($SYS_,x),%eax; KERNCALL; jb 2b #define RSYSCALL(x) SYSCALL(x); ret #define KERNCALL int $0x80
とマクロの嵐ですが、何となく __sys_read &read というシンボルが呼ばれると、int 0x80 ソフトウェア割り込みでシステムコールが呼び出されているような気がします。
そうすると、以下のようになっているのかなぁ。と。
fread() の場合: _read() -> __sys_read() 経由でシステムコール呼び出し
read() の場合: 直接システムコール呼び出し