SlideShare uma empresa Scribd logo
1 de 49
Baixar para ler offline
libcのputcharについて
 
      スタート低レイヤー#3 #start_printf
 
 
                @kusabanachi
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で書き込みしているぽい
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;
}
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) )
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関数が割り当てられている
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 の処理をはさんでロックしている
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の定義が指定されている
__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;
}
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に準拠しているか
 => 普通のコンパイルではこちらのコードが使われるだろう
次に続く、__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を使う場合に合理的なコードを出力する版 */
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に移る。
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へ進む
/******************************************************************
putchar
            ... stdoutに1文字書き込み
=> __sputc
            ... バッファに書き込み、貯まったら__swbufへ
******************************************************************/
__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);
 
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なのでバイト単位に設定。
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を呼ぶ条件を満たすよう)にする。
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のバッファはここで初めて割り当てられる
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がバッファのサイズ以上なら、"すでに満杯"なのでフラッシュす
る。
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'の書き込みならフラッシュする
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の戻り値になる。
/******************************************************************
putchar
            ... stdoutに1文字書き込み
=> __sputc
            ... バッファに書き込み、貯まったら__swbufへ
 => __swbuf
            ... バッファの初期化、バッファ貯まってたらfflushへ
******************************************************************/
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;
}
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を適用している
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)を呼ぶ。
/******************************************************************
putchar
            ... stdoutに1文字書き込み
=> __sputc
            ... バッファに書き込み、貯まったら__swbufへ
 => __swbuf
            ... バッファの初期化、バッファ貯まってたらfflushへ
  => fflush
            ... 引数NULLなら全ファイル、もしくは1ファイルを__sflush
******************************************************************/
__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 */
 
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フラグがなければ戻る
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にバッファの先頭位置を入れる
バッファが無ければ戻る
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 はバッファの 現在位置 - 先頭。
なので、書き込みサイズ
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の値を初期化している(理由は上のコメント)
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になるまで書き込む
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で戻る。
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
/******************************************************************
putchar
            ... stdoutに1文字書き込み
=> __sputc
            ... バッファに書き込み、貯まったら__swbufへ
 => __swbuf
            ... バッファの初期化、バッファ貯まってたらfflushへ
  => fflush
            ... 引数NULLなら全ファイル、もしくは1ファイルを__sflush
   => __sflush
            ... バッファに貯まったサイズを全てfile­>_writeで書く
******************************************************************/
__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);
}
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でファイル末尾にオフセットを移
動する
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フラグを消す
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はどこか?
/******************************************************************
putchar
            ... stdoutに1文字書き込み
=> __sputc
            ... バッファに書き込み、貯まったら__swbufへ
 => __swbuf
            ... バッファの初期化、バッファ貯まってたらfflushへ
  => fflush
            ... 引数NULLなら全ファイル、もしくは1ファイルを__sflush
   => __sflush
            ... バッファに貯まったサイズを全てfile­>_writeで書く
    => __swrite :: (file­>_write)
            ... 追記フラグをチェックしてwriteを呼ぶ
******************************************************************/
write
 
 
writeのcソースファイルは見つからない
gdb ステップ実行画面
0xbbbbfe1e in __swrite () from /usr/lib/libc.so.12
(gdb)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
__swrite関数からgdbでステップ実行をしていきます
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がコールされる。
(初回は動的リンクが行われる)
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内にあった
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のアセンブリコードを表示します
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
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    割り込みベクタ番号の即値バイトによる指定。
write(の始めの2行)まとめ
=> 0xbbaf9080 <+0>:    mov    $0x4,%eax
   0xbbaf9085 <+5>:    int    $0x80
write関数はwriteシステムコールの番号をEAXレジスタに書いて、
int 0x80を実行する
intは割り込みハンドラをコールする命令。
(IA-32 マニュアルより)
0x80はおそらく、システムコールに対応する
割り込みベクタ番号のはず
(だけど、それを示すコードは見つけられなかった...)
 
(int以降のアセンブリも読めていません...)
/******************************************************************
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)
            ... ?
******************************************************************/
終わり

Mais conteúdo relacionado

Mais procurados

PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説do_aki
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とdo_aki
 
cdev_write and_comwrite
cdev_write and_comwritecdev_write and_comwrite
cdev_write and_comwritekusabanachi
 
PHPでマルチスレッド
PHPでマルチスレッドPHPでマルチスレッド
PHPでマルチスレッドkarky7
 
dofilewrite and vn_write
dofilewrite and vn_writedofilewrite and vn_write
dofilewrite and vn_writekusabanachi
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Mr. Vengineer
 
Elog and Ebuild Phase Hook
Elog and Ebuild Phase HookElog and Ebuild Phase Hook
Elog and Ebuild Phase HookYasuhiro Asaka
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側do_aki
 
ナウなヤングにバカうけのイカしたタグ付き共用体
ナウなヤングにバカうけのイカしたタグ付き共用体ナウなヤングにバカうけのイカしたタグ付き共用体
ナウなヤングにバカうけのイカしたタグ付き共用体digitalghost
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かdo_aki
 
LLVM overview 20110122
LLVM overview 20110122LLVM overview 20110122
LLVM overview 20110122nothingcosmos
 
エラーハンドリング
エラーハンドリングエラーハンドリング
エラーハンドリング道化師 堂華
 
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compilerAdaptive optimization of JIT compiler
Adaptive optimization of JIT compilernothingcosmos
 
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチンyohhoy
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1信之 岩永
 

Mais procurados (20)

PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 と
 
cdev_write and_comwrite
cdev_write and_comwritecdev_write and_comwrite
cdev_write and_comwrite
 
PHPでマルチスレッド
PHPでマルチスレッドPHPでマルチスレッド
PHPでマルチスレッド
 
dofilewrite and vn_write
dofilewrite and vn_writedofilewrite and vn_write
dofilewrite and vn_write
 
ttwrite
ttwritettwrite
ttwrite
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
 
C++11
C++11C++11
C++11
 
Elog and Ebuild Phase Hook
Elog and Ebuild Phase HookElog and Ebuild Phase Hook
Elog and Ebuild Phase Hook
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側
 
ナウなヤングにバカうけのイカしたタグ付き共用体
ナウなヤングにバカうけのイカしたタグ付き共用体ナウなヤングにバカうけのイカしたタグ付き共用体
ナウなヤングにバカうけのイカしたタグ付き共用体
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
LLVM overview 20110122
LLVM overview 20110122LLVM overview 20110122
LLVM overview 20110122
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
 
エラーハンドリング
エラーハンドリングエラーハンドリング
エラーハンドリング
 
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compilerAdaptive optimization of JIT compiler
Adaptive optimization of JIT compiler
 
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン
 
C++0x総復習
C++0x総復習C++0x総復習
C++0x総復習
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
 

Semelhante a libcのputcharについて

C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいC++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいdigitalghost
 
Wrapping a C++ library with Cython
Wrapping a C++ library with CythonWrapping a C++ library with Cython
Wrapping a C++ library with Cythonfuzzysphere
 
発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発貴大 山下
 
Boost.Coroutine
Boost.CoroutineBoost.Coroutine
Boost.Coroutinemelpon
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日貴大 山下
 
Programming camp Codereading
Programming camp CodereadingProgramming camp Codereading
Programming camp CodereadingHiro Yoshioka
 
Linux Performance Analysis in 15 minutes
Linux Performance Analysis in 15 minutesLinux Performance Analysis in 15 minutes
Linux Performance Analysis in 15 minutesYohei Azekatsu
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputingNoboru Irieda
 
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部Kiyoshi Ogawa
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。Kazuki Onishi
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングKiwamu Okabe
 
Stellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイドStellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイドryos36
 
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)Ryuuta Tsunashima
 
X tapp lecture_20140226_tapioca
X tapp lecture_20140226_tapiocaX tapp lecture_20140226_tapioca
X tapp lecture_20140226_tapiocaxTAPP
 
Hello, Guava ! samples
Hello, Guava ! samplesHello, Guava ! samples
Hello, Guava ! samples輝 子安
 
OCamlのトップレベルあれそれ
OCamlのトップレベルあれそれOCamlのトップレベルあれそれ
OCamlのトップレベルあれそれnomaddo
 

Semelhante a libcのputcharについて (20)

C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいC++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みください
 
Wrapping a C++ library with Cython
Wrapping a C++ library with CythonWrapping a C++ library with Cython
Wrapping a C++ library with Cython
 
発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発
 
Boost.Coroutine
Boost.CoroutineBoost.Coroutine
Boost.Coroutine
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
カーネルモジュールプログラミング超入門 #1(仮)
カーネルモジュールプログラミング超入門 #1(仮)カーネルモジュールプログラミング超入門 #1(仮)
カーネルモジュールプログラミング超入門 #1(仮)
 
高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日
 
Programming camp Codereading
Programming camp CodereadingProgramming camp Codereading
Programming camp Codereading
 
Linux Performance Analysis in 15 minutes
Linux Performance Analysis in 15 minutesLinux Performance Analysis in 15 minutes
Linux Performance Analysis in 15 minutes
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
 
Acct v3 binary
Acct v3 binaryAcct v3 binary
Acct v3 binary
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
 
Stellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイドStellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイド
 
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
 
X tapp lecture_20140226_tapioca
X tapp lecture_20140226_tapiocaX tapp lecture_20140226_tapioca
X tapp lecture_20140226_tapioca
 
Hello, Guava ! samples
Hello, Guava ! samplesHello, Guava ! samples
Hello, Guava ! samples
 
ILE-RPG Study 001
ILE-RPG Study 001ILE-RPG Study 001
ILE-RPG Study 001
 
OCamlのトップレベルあれそれ
OCamlのトップレベルあれそれOCamlのトップレベルあれそれ
OCamlのトップレベルあれそれ
 

libcのputcharについて