Enviar pesquisa
Carregar
libcのputcharについて
•
0 gostou
•
979 visualizações
K
kusabanachi
Seguir
NetBSD-6.0.1のソースコードリーディング。
Leia menos
Leia mais
Denunciar
Compartilhar
Denunciar
Compartilhar
1 de 49
Baixar agora
Baixar para ler offline
Recomendados
Dive into RTS - another side
Dive into RTS - another side
Kiwamu Okabe
Zynq VIPを利用したテストベンチ
Zynq VIPを利用したテストベンチ
Mr. Vengineer
バグベアード入門
バグベアード入門
道化師 堂華
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
Mr. Vengineer
ZynqMPのQEMU
ZynqMPのQEMU
Mr. Vengineer
OPcache の最適化器の今
OPcache の最適化器の今
y-uti
php-src の歩き方
php-src の歩き方
do_aki
gen-class とバイトコード(第3回 gen-class 勉強会資料)
gen-class とバイトコード(第3回 gen-class 勉強会資料)
tnoda
Recomendados
Dive into RTS - another side
Dive into RTS - another side
Kiwamu Okabe
Zynq VIPを利用したテストベンチ
Zynq VIPを利用したテストベンチ
Mr. Vengineer
バグベアード入門
バグベアード入門
道化師 堂華
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
Mr. Vengineer
ZynqMPのQEMU
ZynqMPのQEMU
Mr. Vengineer
OPcache の最適化器の今
OPcache の最適化器の今
y-uti
php-src の歩き方
php-src の歩き方
do_aki
gen-class とバイトコード(第3回 gen-class 勉強会資料)
gen-class とバイトコード(第3回 gen-class 勉強会資料)
tnoda
PHP AST 徹底解説
PHP AST 徹底解説
do_aki
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 と
do_aki
cdev_write and_comwrite
cdev_write and_comwrite
kusabanachi
PHPでマルチスレッド
PHPでマルチスレッド
karky7
dofilewrite and vn_write
dofilewrite and vn_write
kusabanachi
ttwrite
ttwrite
kusabanachi
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
Mr. Vengineer
C++11
C++11
京大 マイコンクラブ
Elog and Ebuild Phase Hook
Elog and Ebuild Phase Hook
Yasuhiro Asaka
PHPとシグナル、その裏側
PHPとシグナル、その裏側
do_aki
ナウなヤングにバカうけのイカしたタグ付き共用体
ナウなヤングにバカうけのイカしたタグ付き共用体
digitalghost
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
do_aki
VerilatorとSystemC
VerilatorとSystemC
Mr. Vengineer
LLVM overview 20110122
LLVM overview 20110122
nothingcosmos
emc++ chapter32
emc++ chapter32
Tatsuki SHIMIZU
エラーハンドリング
エラーハンドリング
道化師 堂華
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compiler
nothingcosmos
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン
yohhoy
C++0x総復習
C++0x総復習
道化師 堂華
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
信之 岩永
C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みください
digitalghost
Wrapping a C++ library with Cython
Wrapping a C++ library with Cython
fuzzysphere
Mais conteúdo relacionado
Mais procurados
PHP AST 徹底解説
PHP AST 徹底解説
do_aki
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 と
do_aki
cdev_write and_comwrite
cdev_write and_comwrite
kusabanachi
PHPでマルチスレッド
PHPでマルチスレッド
karky7
dofilewrite and vn_write
dofilewrite and vn_write
kusabanachi
ttwrite
ttwrite
kusabanachi
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
Mr. Vengineer
C++11
C++11
京大 マイコンクラブ
Elog and Ebuild Phase Hook
Elog and Ebuild Phase Hook
Yasuhiro Asaka
PHPとシグナル、その裏側
PHPとシグナル、その裏側
do_aki
ナウなヤングにバカうけのイカしたタグ付き共用体
ナウなヤングにバカうけのイカしたタグ付き共用体
digitalghost
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
do_aki
VerilatorとSystemC
VerilatorとSystemC
Mr. Vengineer
LLVM overview 20110122
LLVM overview 20110122
nothingcosmos
emc++ chapter32
emc++ chapter32
Tatsuki SHIMIZU
エラーハンドリング
エラーハンドリング
道化師 堂華
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compiler
nothingcosmos
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン
yohhoy
C++0x総復習
C++0x総復習
道化師 堂華
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
信之 岩永
Mais procurados
(20)
PHP AST 徹底解説
PHP AST 徹底解説
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 と
cdev_write and_comwrite
cdev_write and_comwrite
PHPでマルチスレッド
PHPでマルチスレッド
dofilewrite and vn_write
dofilewrite and vn_write
ttwrite
ttwrite
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
C++11
C++11
Elog and Ebuild Phase Hook
Elog and Ebuild Phase Hook
PHPとシグナル、その裏側
PHPとシグナル、その裏側
ナウなヤングにバカうけのイカしたタグ付き共用体
ナウなヤングにバカうけのイカしたタグ付き共用体
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
VerilatorとSystemC
VerilatorとSystemC
LLVM overview 20110122
LLVM overview 20110122
emc++ chapter32
emc++ chapter32
エラーハンドリング
エラーハンドリング
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compiler
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン
C++0x総復習
C++0x総復習
C# 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からのメッセージをお読みください
digitalghost
Wrapping a C++ library with Cython
Wrapping a C++ library with Cython
fuzzysphere
発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発
貴大 山下
Boost.Coroutine
Boost.Coroutine
melpon
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
伸男 伊藤
カーネルモジュールプログラミング超入門 #1(仮)
カーネルモジュールプログラミング超入門 #1(仮)
University of Tsukuba Linux User Group
高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日
貴大 山下
Programming camp Codereading
Programming camp Codereading
Hiro Yoshioka
Linux Performance Analysis in 15 minutes
Linux Performance Analysis in 15 minutes
Yohei Azekatsu
Python physicalcomputing
Python physicalcomputing
Noboru Irieda
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
Kiyoshi Ogawa
Acct v3 binary
Acct v3 binary
Yutaka Matsuzawa
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
Kiwamu Okabe
Stellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイド
ryos36
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
Ryuuta Tsunashima
X tapp lecture_20140226_tapioca
X tapp lecture_20140226_tapioca
xTAPP
Hello, Guava ! samples
Hello, Guava ! samples
輝 子安
ILE-RPG Study 001
ILE-RPG Study 001
Yoshiki Ushida
OCamlのトップレベルあれそれ
OCamlのトップレベルあれそれ
nomaddo
Semelhante a libcのputcharについて
(20)
C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みください
Wrapping a C++ library with Cython
Wrapping a C++ library with Cython
発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発
Boost.Coroutine
Boost.Coroutine
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
カーネルモジュールプログラミング超入門 #1(仮)
カーネルモジュールプログラミング超入門 #1(仮)
高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日
Programming camp Codereading
Programming camp Codereading
Linux Performance Analysis in 15 minutes
Linux Performance Analysis in 15 minutes
Python physicalcomputing
Python physicalcomputing
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
Acct v3 binary
Acct v3 binary
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
Stellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイド
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
X tapp lecture_20140226_tapioca
X tapp lecture_20140226_tapioca
Hello, Guava ! samples
Hello, Guava ! samples
ILE-RPG Study 001
ILE-RPG Study 001
OCamlのトップレベルあれそれ
OCamlのトップレベルあれそれ
libcのputcharについて
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.
終わり
Baixar agora