Your SlideShare is downloading. ×
0
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
libcのputcharについて
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

libcのputcharについて

389

Published on

NetBSD-6.0.1のソースコードリーディング。

NetBSD-6.0.1のソースコードリーディング。

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
389
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. libcのputcharについて         スタート低レイヤー#3 #start_printf                     @kusabanachi
  • 2. putchar src/lib/libc/stdio/putchar.c 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /*  * A subroutine version of the macro putchar  */ int putchar(c)     int c; {     FILE *fp = stdout;         int r;       FLOCKFILE(fp);     r = __sputc(c, fp);     FUNLOCKFILE(fp);     return r; } 引数の文字cを、stdout(標準出力)に __sputcで書き込みしているぽい
  • 3. stdout src/lib/libc/stdio/putchar.c 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /*  * A subroutine version of the macro putchar  */ int putchar(c)     int c; {     FILE *fp = stdout;         int r;       FLOCKFILE(fp);     r = __sputc(c, fp);     FUNLOCKFILE(fp);     return r; }
  • 4. src/include/stdio.h 215 #define    stdout    (&__sF[1]) src/lib/libc/stdio/findfp.c 81 82 83 84 85 FILE __sF[3] = {     std(__SRD, STDIN_FILENO),        /* stdin */     std(__SWR, STDOUT_FILENO),        /* stdout */     std(__SWR|__SNBF, STDERR_FILENO)    /* stderr */ }; src/include/stdio.h 152 153 154 155 #define    __SNBF    0x0002        /* unbuffered */ #define    __SRD    0x0004        /* OK to read */ #define    __SWR    0x0008        /* OK to write */     /* RD and WR are never simultaneously asserted */ src/include/unistd.h 80 81 82 #define    STDIN_FILENO    0    /* standard input file descriptor */ #define    STDOUT_FILENO    1    /* standard output file descriptor */ #define    STDERR_FILENO    2    /* standard error file descriptor */ stdin, stdout, stderrが __SF[3] に格納されている。 stdoutは std( WRフラグ, ファイル識別子番号(1) )
  • 5. src/lib/libc/stdio/findfp.c 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #define    std(flags, file) {      ._p = NULL,      ._r = 0,      ._w = 0,      ._flags = (flags),      ._file = (file),       ._bf = { ._base = NULL, ._size = 0 },      ._lbfsize = 0,       ._cookie = __sF + (file),      ._close = __sclose,      ._read = __sread,      ._seek = __sseek,      ._write = __swrite,      ._ext = { ._base = (void *)(__sFext + (file)), ._size = 0 },      ._up = NULL,      ._ur = 0,      ._ubuf = { [0] = '0', [1] = '0', [2] = '0' },      ._nbuf = { [0] = '0' },      ._flush = NULL,      ._lb_unused = { '0' },      ._blksize = 0,      ._offset = (off_t)0,  } stdはFILE構造体のメンバを初期化するマクロ close, read, seek, write関数が割り当てられている
  • 6. FLOCKFILE, FUNLOCKFILE src/lib/libc/stdio/putchar.c 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /*  * A subroutine version of the macro putchar  */ int putchar(c)     int c; {     FILE *fp = stdout;         int r;       FLOCKFILE(fp);     r = __sputc(c, fp);     FUNLOCKFILE(fp);     return r; } __sputc の処理をはさんでロックしている
  • 7. src/lib/libc/include/reentrant.h #ifdef _REENTRANT ... #define    FLOCKFILE(fp)        __flockfile_internal(fp, 1) #define    FUNLOCKFILE(fp)        __funlockfile_internal(fp, 1)   #else /* _REENTRANT */ ... #define    FLOCKFILE(fp)         #define    FUNLOCKFILE(fp)           #endif /* _REENTRANT */ _REENTRANT が定義されている時は処理を行っている 再入可能なプログラムで、ファイルを扱うためのロックのようだ   src/lib/libc/Makefile.inc 27 CPPFLAGS+=    ­D_LIBC ­DLIBC_SCCS ­DSYSLIBC_SCCS ­D_REENTRANT libcのMakefileで_REENTRANTの定義が指定されている
  • 8. __sputc src/lib/libc/stdio/putchar.c 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /*  * A subroutine version of the macro putchar  */ int putchar(c)     int c; {     FILE *fp = stdout;         int r;       FLOCKFILE(fp);     r = __sputc(c, fp);     FUNLOCKFILE(fp);     return r; }
  • 9. src/include/stdio.h 447 448 449 450 451 452 453 454 455 456 457 458 459 460 /*  * The __sfoo macros are here so that we can   * define function versions in the C library.  */ #define    __sgetc(p) (­­(p)­>_r < 0 ? __srget(p) : (int)(*(p)­>_p++)) #if defined(__GNUC__) && defined(__STDC__) static __inline int __sputc(int _c, FILE *_p) {     if (­­_p­>_w >= 0 || (_p­>_w >= _p­>_lbfsize && (char)_c != 'n'         return (*_p­>_p++ = _c);     else         return (__swbuf(_c, _p)); } #else ... /* Cライブラリ内で関数のバージョン群を定義するため、    __sfooマクロ群はここにある */  →いくつかの異なる処理を定義(分岐)したかった?   __GNUC__ はGNUコンパイラのメジャー番号 __STDC__ はコンパイラがISO標準Cに準拠しているか  => 普通のコンパイルではこちらのコードが使われるだろう
  • 10. 次に続く、__GNUC__ または __STDC__ が定義されていない場合 の__sputcは 459 460 461 462 463 464 465 466 467 468 469 470 471 #else /*  * This has been tuned to generate reasonable code on the vax using pcc.  */ #define    __sputc(c, p)      (­­(p)­>_w < 0 ?          (p)­>_w >= (p)­>_lbfsize ?              (*(p)­>_p = (c)), *(p)­>_p != 'n' ?                  (int)*(p)­>_p++ :                  __swbuf('n', p) :              __swbuf((int)(c), p) :          (*(p)­>_p = (c), (int)*(p)­>_p++)) #endif /* これは、vax上でpccを使う場合に合理的なコードを出力する版 */
  • 11. src/include/stdio.h ファイル構造体から typedef    struct __sFILE {     unsigned char *_p;    /* バッファ内の現在位置   current position in (some) buff     int    _w;        /* 残っているwriteスペース   write space left for putc() */     int    _lbfsize;    /* 0、またはラインバッファ時はバッファのサイズの負の値   0 or ­_b   バッファ無しでなければ、バッファに貯まってから下層のwriteが行 われる。 _wが_lbfsizeより値が小さくなるか、ラインバッファの改行で 下層のwriteに移る。
  • 12. src/include/stdio.h ファイル構造体から抜粋 typedef    struct __sFILE {     unsigned char *_p;    /* バッファ内の現在位置   current position in (some) buff     int    _w;        /* 残っているwriteスペース   write space left for putc() */     int    _lbfsize;    /* 0、またはラインバッファ時はバッファのサイズの負の値   0 or ­_b   * (__GNUC__) && (__STDC__) 版の __putc をもう一度見ます #if defined(__GNUC__) && defined(__STDC__) static __inline int __sputc(int _c, FILE *_p) {   // ファイルの_wをデクリメント   if (­­_p­>_w >= 0 || (_p­>_w >= _p­>_lbfsize && (char)_c != 'n'))     // _wが0より大きい ||                           <通常のバッファ、貯め中>     // (_wが_lbfsizeより大きく && 文字が改行でない)   <ラインバッファ、貯め中>     return (*_p­>_p++ = _c);   // ファイルのバッファに書いて終わり   else     // そうでない場合     return (__swbuf(_c, _p));  // __swbufに処理を委せる } stdoutの初期値は_wやバッファサイズが0なので、 1回目は__swbufへ進む
  • 13. /****************************************************************** putchar             ... stdoutに1文字書き込み => __sputc             ... バッファに書き込み、貯まったら__swbufへ ******************************************************************/
  • 14. __swbuf src/lib/libc/stdio/wbuf.c 1/3 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /*  * 引数の文字cを、引数fpの(たぶん満杯な)バッファに書く。  * バッファがすでに満杯だったり、満杯になる場合、または  * c=='n'(ラインバッファ時)なら、フラッシュする。  */ int __swbuf(c, fp)     int c;     FILE *fp; {     int n;       _DIAGASSERT(fp != NULL);       _SET_ORIENTATION(fp, ­1);  
  • 15. src/lib/libc/stdio/wbuf.c 1/3 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /*  * 引数の文字cを、引数fpの(たぶん満杯な)バッファに書く。  * バッファがすでに満杯だったり、満杯になる場合、または  * c=='n'(ラインバッファ時)なら、フラッシュする。  */ int __swbuf(c, fp)     int c;     FILE *fp; {     int n;       _DIAGASSERT(fp != NULL);       _SET_ORIENTATION(fp, ­1);   _SET_ORIENTATION()は、FILEの入出力単位を ワイド文字かバイトか設定する。 引数-1なのでバイト単位に設定。
  • 16. src/lib/libc/stdio/wbuf.c 2/3 66 67 68 69 70 71 72 73 74 75 76 77 78 79 /*  * writeできないか、早期にlongjmpで追い出される場合は、  * またここに呼ばれるために、_wが 0(バッファが満杯かバッファ無し)  * または­_bf._sizeと等しい(ラインバッファ時)ようにすること。  * それをしないと、十分な数のputc()が、  * _wを負数から正数にしてしまうかもしれない。  */ fp­>_w = fp­>_lbfsize; if (cantwrite(fp)) {     errno = EBADF;     return (EOF); } c = (unsigned char)c; コメントに書いてあることの対処として、 _wの値を_lvfsize(__swbufを呼ぶ条件を満たすよう)にする。
  • 17. src/lib/libc/stdio/wbuf.c 2/3 66 67 68 69 70 71 72 73 74 75 76 77 78 79 /*  * writeできないか、早期にlongjmpで追い出される場合は、  * _wが 0(満杯かバッファ無し)または ­_bf._sizeと等しい  * (ラインバッファの場合)事を、またここに呼ばれるために確認すること。  * それをしないと、十分な数のputc()が、  * _wを負数から正数にしてしまうかもしれない。  */ fp­>_w = fp­>_lbfsize; if (cantwrite(fp)) {     errno = EBADF;     return (EOF); } c = (unsigned char)c; canwriteはfpの書き込みフラグとバッファの有無をチェックする。 どちらかが無い場合は、フラグとバッファをセットアップする。 stdoutのバッファはここで初めて割り当てられる
  • 18. src/lib/libc/stdio/wbuf.c 3/3 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101     /*      * すでに満杯ならフラッシュする。その後、どちらにしろcをバッファに      * 詰めこむ。それでバッファが満杯になったり、      * cが'n'でラインバッファなら、フラッシュする(たぶん2回目のフラッシュで)。      * 2回目のフラッシュは`_bf._size==1`のバッファ無しならいつも起こる。      * fflush()は、putc()がいつも_wを0にして      * wbuf()をコールすることを保証するから、      * 私達は他に何かする必要はない。      */     n = fp­>_p ­ fp­>_bf._base;     if (n >= fp­>_bf._size) {         if (fflush(fp))             return (EOF);         n = 0;     }     fp­>_w­­;     *fp­>_p++ = c;     if (++n == fp­>_bf._size || (fp­>_flags & __SLBF && c == 'n'))         if (fflush(fp))             return (EOF);     return (c); } nはバッファ内に書き込んであるサイズ。 nがバッファのサイズ以上なら、"すでに満杯"なのでフラッシュす る。
  • 19. src/lib/libc/stdio/wbuf.c 3/3 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101     /*      * すでに満杯ならフラッシュする。その後、どちらにしろcをバッファに      * 詰めこむ。それでバッファが満杯になったり、      * cが'n'でラインバッファなら、フラッシュする(たぶん2回目のフラッシュで)。      * 2回目のフラッシュは`_bf._size==1`のバッファ無しならいつも起こる。      * fflush()は、putc()がいつも_wを0にして      * wbuf()をコールすることを保証するから、      * 私達は他に何かする必要はない。      */     n = fp­>_p ­ fp­>_bf._base;     if (n >= fp­>_bf._size) {         if (fflush(fp))             return (EOF);         n = 0;     }     fp­>_w­­;     *fp­>_p++ = c;     if (++n == fp­>_bf._size || (fp­>_flags & __SLBF && c == 'n'))         if (fflush(fp))             return (EOF);     return (c); } fpのバッファにcを書き込む。 nをインクリメントして、バッファの サイズと等しければ"満杯になった"。 または、ラインバッファで'n'の書き込みならフラッシュする
  • 20. src/lib/libc/stdio/wbuf.c 3/3 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101     /*      * すでに満杯ならフラッシュする。その後、どちらにしろcをバッファに      * 詰めこむ。それでバッファが満杯になったり、      * cが'n'でラインバッファなら、フラッシュする(たぶん2回目のフラッシュで)。      * 2回目のフラッシュは`_bf._size==1`のバッファ無しならいつも起こる。      * fflush()は、putc()がいつも_wを0にして      * wbuf()をコールすることを保証するから、      * 私達は他に何かする必要はない。      */     n = fp­>_p ­ fp­>_bf._base;     if (n >= fp­>_bf._size) {         if (fflush(fp))             return (EOF);         n = 0;     }     fp­>_w­­;     *fp­>_p++ = c;     if (++n == fp­>_bf._size || (fp­>_flags & __SLBF && c == 'n'))         if (fflush(fp))             return (EOF);     return (c); } fflushは0の戻り値が成功で、その時100行目に到達して __swbufは書き込んだ文字cを返す。 失敗時は__swbufはEOFを返して、それがputharの戻り値になる。
  • 21. /****************************************************************** putchar             ... stdoutに1文字書き込み => __sputc             ... バッファに書き込み、貯まったら__swbufへ  => __swbuf             ... バッファの初期化、バッファ貯まってたらfflushへ ******************************************************************/
  • 22. fflush src/lib/libc/stdio/fflush.c 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 /* 1つのファイルか, (fpが NULLの場合) 全てのファイルをフラッシュする.  */ int fflush(fp)     FILE *fp; {     int r;       if (fp == NULL) {         rwlock_rdlock(&__sfp_lock);         r = _fwalk(__sflush);         rwlock_unlock(&__sfp_lock);         return r;     }       FLOCKFILE(fp);     if ((fp­>_flags & (__SWR | __SRW)) == 0) {         errno = EBADF;         r = EOF;     } else {         r = __sflush(fp);     }     FUNLOCKFILE(fp);     return r; }
  • 23. src/lib/libc/stdio/fflush.c 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 /* 1つのファイルか, (fpが NULLの場合) 全てのファイルをフラッシュする.  */ int fflush(fp)     FILE *fp; {     int r;       if (fp == NULL) {         rwlock_rdlock(&__sfp_lock);         r = _fwalk(__sflush);         rwlock_unlock(&__sfp_lock);         return r;     }       FLOCKFILE(fp);     if ((fp­>_flags & (__SWR | __SRW)) == 0) {         errno = EBADF;         r = EOF;     } else {         r = __sflush(fp);     }     FUNLOCKFILE(fp);     return r; } fp == NULLの場合、_fwalkで全てのファイルを辿って 各ファイルに __sflushを適用している
  • 24. src/lib/libc/stdio/fflush.c 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 /* 1つのファイルか, (fpが NULLの場合) 全てのファイルをフラッシュする.  */ int fflush(fp)     FILE *fp; {     int r;       if (fp == NULL) {         rwlock_rdlock(&__sfp_lock);         r = _fwalk(__sflush);         rwlock_unlock(&__sfp_lock);         return r;     }       FLOCKFILE(fp);     if ((fp­>_flags & (__SWR | __SRW)) == 0) {         errno = EBADF;         r = EOF;     } else {         r = __sflush(fp);     }     FUNLOCKFILE(fp);     return r; } writeとread&write、両方無ければエラー。 そうでなければ、__sflush(fp)を呼ぶ。
  • 25. /****************************************************************** putchar             ... stdoutに1文字書き込み => __sputc             ... バッファに書き込み、貯まったら__swbufへ  => __swbuf             ... バッファの初期化、バッファ貯まってたらfflushへ   => fflush             ... 引数NULLなら全ファイル、もしくは1ファイルを__sflush ******************************************************************/
  • 26. __sflush src/lib/libc/stdio/fflush.c 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 int __sflush(fp)     FILE *fp; {     unsigned char *p;     int n, t;       _DIAGASSERT(fp != NULL);       t = fp­>_flags;     if ((t & __SWR) == 0)         return (0);       if ((p = fp­>_bf._base) == NULL)         return (0);       n = fp­>_p ­ p;        /* write this much */  
  • 27. src/lib/libc/stdio/fflush.c 1/2 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 int __sflush(fp)     FILE *fp; {     unsigned char *p;     int n, t;       _DIAGASSERT(fp != NULL);       t = fp­>_flags;     if ((t & __SWR) == 0)         return (0);       if ((p = fp­>_bf._base) == NULL)         return (0);       n = fp­>_p ­ p;        /* write this much */   writeフラグがなければ戻る
  • 28. src/lib/libc/stdio/fflush.c 1/2 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 int __sflush(fp)     FILE *fp; {     unsigned char *p;     int n, t;       _DIAGASSERT(fp != NULL);       t = fp­>_flags;     if ((t & __SWR) == 0)         return (0);       if ((p = fp­>_bf._base) == NULL)         return (0);       n = fp­>_p ­ p;        /* write this much */   pにバッファの先頭位置を入れる バッファが無ければ戻る
  • 29. src/lib/libc/stdio/fflush.c 1/2 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 int __sflush(fp)     FILE *fp; {     unsigned char *p;     int n, t;       _DIAGASSERT(fp != NULL);       t = fp­>_flags;     if ((t & __SWR) == 0)         return (0);       if ((p = fp­>_bf._base) == NULL)         return (0);       n = fp­>_p ­ p;        /* write this much */   n はバッファの 現在位置 - 先頭。 なので、書き込みサイズ
  • 30. src/lib/libc/stdio/fflush.c 2/2 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112     /*      * longjmpの問題の回避と、ユーザーのwrite関数での      * バッファの交換(setvbuf経由)の許可のため、即座にこれらをセットする。      */     fp­>_p = p;     fp­>_w = t & (__SLBF|__SNBF) ? 0 : fp­>_bf._size;       for (; n > 0; n ­= t, p += t) {         t = (*fp­>_write)(fp­>_cookie, (char *)p, n);         if (t <= 0) {             fp­>_flags |= __SERR;             return (EOF);         }     }     return (0); } バッファの現在位置_pを、バッファの先頭に変える。 ラインバッファ か バッファ無しなら、_wは0。 どちらでもなければ、_wはバッファのサイズにする。   これは、_pと_wの値を初期化している(理由は上のコメント)
  • 31. src/lib/libc/stdio/fflush.c 2/2 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112     /*      * longjmpの問題の回避と、ユーザーのwrite関数での      * バッファの交換(setvbuf経由)の許可のため、即座にこれらをセットする。      */     fp­>_p = p;     fp­>_w = t & (__SLBF|__SNBF) ? 0 : fp­>_bf._size;       for (; n > 0; n ­= t, p += t) {         t = (*fp­>_write)(fp­>_cookie, (char *)p, n);         if (t <= 0) {             fp­>_flags |= __SERR;             return (EOF);         }     }     return (0); } ファイル構造体の_write関数をコールする。   fp->_writeの戻り値t は書き込んだサイズ 書き込みサイズのnになるまで書き込む
  • 32. src/lib/libc/stdio/fflush.c 2/2 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112     /*      * longjmpの問題の回避と、ユーザーのwrite関数での      * バッファの交換(setvbuf経由)の許可のため、即座にこれらをセットする。      */     fp­>_p = p;     fp­>_w = t & (__SLBF|__SNBF) ? 0 : fp­>_bf._size;       for (; n > 0; n ­= t, p += t) {         t = (*fp­>_write)(fp­>_cookie, (char *)p, n);         if (t <= 0) {             fp­>_flags |= __SERR;             return (EOF);         }     }     return (0); } 負の値が返ってきたら、エラーを設定して、EOFで戻る。
  • 33. stdoutの定義を確認 src/lib/libc/stdio/findfp.c 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #define    std(flags, file) {      ._p = NULL,      ._r = 0,      ._w = 0,      ._flags = (flags),      ._file = (file),       ._bf = { ._base = NULL, ._size = 0 },      ._lbfsize = 0,       ._cookie = __sF + (file),      ._close = __sclose,      ._read = __sread,      ._seek = __sseek,      ._write = __swrite,      ._ext = { ._base = (void *)(__sFext + (file)), ._size = 0 },      ._up = NULL,      ._ur = 0,      ._ubuf = { [0] = '0', [1] = '0', [2] = '0' },      ._nbuf = { [0] = '0' },      ._flush = NULL,      ._lb_unused = { '0' },      ._blksize = 0,      ._offset = (off_t)0,  } stdoutの_write関数は__write
  • 34. /****************************************************************** putchar             ... stdoutに1文字書き込み => __sputc             ... バッファに書き込み、貯まったら__swbufへ  => __swbuf             ... バッファの初期化、バッファ貯まってたらfflushへ   => fflush             ... 引数NULLなら全ファイル、もしくは1ファイルを__sflush    => __sflush             ... バッファに貯まったサイズを全てfile­>_writeで書く ******************************************************************/
  • 35. __swrite src/lib/libc/stdio/stdio.c 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 int __swrite(cookie, buf, n)     void *cookie;     char const *buf;     int n; {     FILE *fp = cookie;       _DIAGASSERT(cookie != NULL);     _DIAGASSERT(buf != NULL);       if (fp­>_flags & __SAPP)         (void) lseek(__sfileno(fp), (off_t)0, SEEK_END);     fp­>_flags &= ~__SOFF;    /* in case FAPPEND mode is set */     return write(__sfileno(fp), buf, (size_t)n); }
  • 36. src/lib/libc/stdio/stdio.c 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 int __swrite(cookie, buf, n)     void *cookie;     char const *buf;     int n; {     FILE *fp = cookie;       _DIAGASSERT(cookie != NULL);     _DIAGASSERT(buf != NULL);       if (fp­>_flags & __SAPP)         (void) lseek(__sfileno(fp), (off_t)0, SEEK_END);     fp­>_flags &= ~__SOFF;    /* in case FAPPEND mode is set */     return write(__sfileno(fp), buf, (size_t)n); }   #define    __SAPP    0x0100        /* fdopen()ed in append mode */   追記フラグが立っていたら、lseekでファイル末尾にオフセットを移 動する
  • 37. src/lib/libc/stdio/stdio.c 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 int __swrite(cookie, buf, n)     void *cookie;     char const *buf;     int n; {     FILE *fp = cookie;       _DIAGASSERT(cookie != NULL);     _DIAGASSERT(buf != NULL);       if (fp­>_flags & __SAPP)         (void) lseek(__sfileno(fp), (off_t)0, SEEK_END);     fp­>_flags &= ~__SOFF;    /* in case FAPPEND mode is set */     return write(__sfileno(fp), buf, (size_t)n); }   #define    __SOFF  0x1000   /* set iff _offset is in fact correct */                       /* _offsetの値が正しい時、その時に限ってセットされる */ FAPPENDモードの処理で、 _offsetの値が正しくないかもしれないので __SOFFフラグを消す
  • 38. src/lib/libc/stdio/stdio.c 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 int __swrite(cookie, buf, n)     void *cookie;     char const *buf;     int n; {     FILE *fp = cookie;       _DIAGASSERT(cookie != NULL);     _DIAGASSERT(buf != NULL);       if (fp­>_flags & __SAPP)         (void) lseek(__sfileno(fp), (off_t)0, SEEK_END);     fp­>_flags &= ~__SOFF;    /* in case FAPPEND mode is set */     return write(__sfileno(fp), buf, (size_t)n); } stdoutの __sfileno(fp) は1 write( 識別子番号, バッファのポインタ, 書き込みサイズ );   writeはどこか?
  • 39. /****************************************************************** putchar             ... stdoutに1文字書き込み => __sputc             ... バッファに書き込み、貯まったら__swbufへ  => __swbuf             ... バッファの初期化、バッファ貯まってたらfflushへ   => fflush             ... 引数NULLなら全ファイル、もしくは1ファイルを__sflush    => __sflush             ... バッファに貯まったサイズを全てfile­>_writeで書く     => __swrite :: (file­>_write)             ... 追記フラグをチェックしてwriteを呼ぶ ******************************************************************/
  • 40. write     writeのcソースファイルは見つからない
  • 41. gdb ステップ実行画面 0xbbbbfe1e in __swrite () from /usr/lib/libc.so.12 (gdb)                                         __swrite関数からgdbでステップ実行をしていきます
  • 42. gdb ステップ実行画面 0xbbbbfe1e in __swrite () from /usr/lib/libc.so.12 (gdb) si 0xbbaf5f9c in write@plt () from /usr/lib/libc.so.12 (gdb)                                   ステップ実行を続けると、write@pltがコールされる。 (初回は動的リンクが行われる)
  • 43. gdb ステップ実行画面 0xbbbbfe1e in __swrite () from /usr/lib/libc.so.12 (gdb) si 0xbbaf5f9c in write@plt () from /usr/lib/libc.so.12 (gdb) si 0xbbaf9080 in write () from /usr/lib/libc.so.12 (gdb)                               リンクの完了後だと、write関数にたどり着く。 write関数はlibc内にあった
  • 44. gdb ステップ実行画面 0xbbbbfe1e in __swrite () from /usr/lib/libc.so.12 (gdb) si 0xbbaf5f9c in write@plt () from /usr/lib/libc.so.12 (gdb) si 0xbbaf9080 in write () from /usr/lib/libc.so.12 (gdb) disassemble disassemble Dump of assembler code for function write: => 0xbbaf9080 <+0>:    mov    $0x4,%eax    0xbbaf9085 <+5>:    int    $0x80    0xbbaf9087 <+7>:    jb     0xbbaf908a < write+10 >    0xbbaf9089 <+9>:    ret        0xbbaf908a <+10>:    push   %ebx    0xbbaf908b <+11>:    call   0xbbaf9090 < write+16 >    0xbbaf9090 <+16>:    pop    %ebx    0xbbaf9091 <+17>:    add    $0xd752c,%ebx    0xbbaf9097 <+23>:    mov    ­0x200(%ebx),%ecx    0xbbaf909d <+29>:    pop    %ebx    0xbbaf909e <+30>:    jmp    *%ecx End of assembler dump. (gdb)   writeのアセンブリコードを表示します
  • 45. gdb ステップ実行画面 0xbbbbfe1e in __swrite () from /usr/lib/libc.so.12 (gdb) si 0xbbaf5f9c in write@plt () from /usr/lib/libc.so.12 (gdb) si 0xbbaf9080 in write () from /usr/lib/libc.so.12 (gdb) disassemble disassemble Dump of assembler code for function write: => 0xbbaf9080 <+0>:    mov    $0x4,%eax    0xbbaf9085 <+5>:    int    $0x80    0xbbaf9087 <+7>:    jb     0xbbaf908a < write+10 >    0xbbaf9089 <+9>:    ret        0xbbaf908a <+10>:    push   %ebx    0xbbaf908b <+11>:    call   0xbbaf9090 < write+16 >    0xbbaf9090 <+16>:    pop    %ebx    0xbbaf9091 <+17>:    add    $0xd752c,%ebx    0xbbaf9097 <+23>:    mov    ­0x200(%ebx),%ecx    0xbbaf909d <+29>:    pop    %ebx    0xbbaf909e <+30>:    jmp    *%ecx End of assembler dump. (gdb) src/sys/sys/syscall.h 28 #define    SYS_write    4
  • 46. gdb ステップ実行画面 0xbbbbfe1e in __swrite () from /usr/lib/libc.so.12 (gdb) si 0xbbaf5f9c in write@plt () from /usr/lib/libc.so.12 (gdb) si 0xbbaf9080 in write () from /usr/lib/libc.so.12 (gdb) disassemble disassemble Dump of assembler code for function write: => 0xbbaf9080 <+0>:    mov    $0x4,%eax    0xbbaf9085 <+5>:    int    $0x80    0xbbaf9087 <+7>:    jb     0xbbaf908a < write+10 >    0xbbaf9089 <+9>:    ret        0xbbaf908a <+10>:    push   %ebx    0xbbaf908b <+11>:    call   0xbbaf9090 < write+16 >    0xbbaf9090 <+16>:    pop    %ebx    0xbbaf9091 <+17>:    add    $0xd752c,%ebx    0xbbaf9097 <+23>:    mov    ­0x200(%ebx),%ecx    0xbbaf909d <+29>:    pop    %ebx    0xbbaf909e <+30>:    jmp    *%ecx End of assembler dump. (gdb)   オペコード   命令        説明 CD ib      INT imm8    割り込みベクタ番号の即値バイトによる指定。
  • 47. write(の始めの2行)まとめ => 0xbbaf9080 <+0>:    mov    $0x4,%eax    0xbbaf9085 <+5>:    int    $0x80 write関数はwriteシステムコールの番号をEAXレジスタに書いて、 int 0x80を実行する intは割り込みハンドラをコールする命令。 (IA-32 マニュアルより) 0x80はおそらく、システムコールに対応する 割り込みベクタ番号のはず (だけど、それを示すコードは見つけられなかった...)   (int以降のアセンブリも読めていません...)
  • 48. /****************************************************************** putchar             ... stdoutに1文字書き込み => __sputc             ... バッファに書き込み、貯まったら__swbufへ  => __swbuf             ... バッファの初期化、バッファ貯まってたらfflushへ   => fflush             ... 引数NULLなら全ファイル、もしくは1ファイルを__sflush    => __sflush             ... バッファに貯まったサイズを全てfile­>_writeで書く     => __swrite :: (file­>_write)             ... 追記フラグをチェックしてwriteを呼ぶ      => write             ... EAXにwriteシステムコールの番号を書いて、int 0x80       => int 0x80 (EAX 4)             ... ? ******************************************************************/
  • 49. 終わり

×