コース目次 / 第2章

write()という、依頼の中身を読む

write(fd, buf, count)の3つの引数と返り値の意味を読み解きます。システムコールが引数と返り値を持つ明確な契約であることを理解し、strace -cで呼び出し回数の統計を見ます。

第2章 / 全4章目安 約10分この章のゴール: write()の引数と返り値の意味を理解し、strace -cで統計を見られるようになる

前章の出力を、もう一度見ます。

write(1, "hello, syscall\n", 15hello, syscall
)        = 15

3つの引数と、1つの返り値

write(fd, buf, count)——
第1引数(fd=1) — ファイルディスクリプタ。1は標準出力(画面)を指す、決まった番号です。
第2引数(buf) — 書き込みたいデータの先頭アドレス。straceは中身を“hello, syscall\n”として表示してくれています。
第3引数(count=15) — 書き込みたいバイト数。sizeof(msg) - 1で、末尾のヌル文字を除いた15バイトを指定しました。
返り値(=15) — 実際に書き込めたバイト数です。

「頼んだ数」と「実際に書けた数」が別々にあるのがポイントです。ネットワーク越しの書き込みなどでは、頼んだバイト数より少ない数しか書き込めないことがあります。C言語でwrite()を直接使うコードは、本来この返り値を確認し、書き残しがあれば再度書き込むべきです(今回の最小限のコードは確認していません——教材としての単純化です)。

システムコールは、明確な契約

「画面に文字を出す」という一見あいまいな動作が、write(ファイルディスクリプタ, バッファのアドレス, バイト数)という厳密に定義された引数と返り値を持つ契約に分解されている——これがシステムコールの正体です。同じ番号のシステムコールは、Linuxが動くどんなCPU(x86_64・ARMなど)でも同じ意味を持ちます。sec-asmで見たsyscall命令は、まさにこの契約を呼び出すためのCPU命令でした。

呼び出し回数を、統計で見る

strace -c ./hello
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         1           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0         2           close
  0.00    0.000000           0         2           fstat
  0.00    0.000000           0         8           mmap
  0.00    0.000000           0         3           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         1           brk
  0.00    0.000000           0         2           pread64
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         2           openat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           prlimit64
  0.00    0.000000           0         1           rseq
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000           0        30         1 total

-cは、個々の呼び出しの代わりに種類ごとの回数と所要時間の集計を見せます。実務で「このプログラムは何をたくさんやっているか」をざっくり掴みたいときに便利です。writeの行のcalls列が1——前の章で確認した「1回だけ呼ばれた」という事実が、ここでも数字として裏付けられています。mmapが8回と多いのも、動的リンカがlibcを読み込む過程で何度もメモリ領域を割り当てているためです。

持ち帰る一言

システムコールは、引数と返り値を持つ明確な契約。 write(fd, buf, count) = 実際に書けたバイト数——この形を知っていれば、他のシステムコール(read・openなど)も同じ枠組みで読めます。次でこのコースをまとめます。

こうなっていればOK

卒業まであと1章です。

この章はまだ完了していません。