exit()で行われている処理も見てみよう。
ソースコードはどこにあるだろうか。man 3 exitを参照すると、以下のようになっている。
EXIT(3) Linux Programmer's Manual EXIT(3) NAME exit - cause normal process termination SYNOPSIS #include <stdlib.h> void exit(int status); ...
#includeの部分を見てほしい。exit()はstdlib.hでプロトタイプ宣言がされているようだ。
そしてglibcのトップディレクトリを見ると、stdlibというディレクトリがある。ここにexit()の本体があるのではないだろうか。
[user@localhost ~]$ cd glibc-2.21 [user@localhost glibc-2.21]$ ls stdlib/*exit* stdlib/at_quick_exit.c stdlib/exit.h stdlib/atexit.c stdlib/old_atexit.c stdlib/cxa_at_quick_exit.c stdlib/on_exit.c stdlib/cxa_atexit.c stdlib/quick_exit.c stdlib/cxa_thread_atexit_impl.c stdlib/tst-tls-atexit-lib.c stdlib/exit.c stdlib/tst-tls-atexit.c [user@localhost glibc-2.21]$
exit.cというファイルがある。見てみると、exit()が以下のように定義されていた。
101:void
102:exit (int status)
103:{
104: __run_exit_handlers (status, &__exit_funcs, true);
105:}
__run_exit_handlers()という関数が呼ばれるようだ。そして__run_exit_handlers()は同一ファイル内で以下のように定義されていた。
28:/* Call all functions registered with `atexit' and `on_exit',
29: in the reverse of the order in which they were registered
30: perform stdio cleanup, and terminate program execution with STATUS. */
31:void
32:attribute_hidden
33:__run_exit_handlers (int status, struct exit_function_list **listp,
34: bool run_list_atexit)
35:{
...
42: /* We do it this way to handle recursive calls to exit () made by
43: the functions registered with `atexit' and `on_exit'. We call
44: everyone on the list and use the status value in the last
45: exit (). */
46: while (*listp != NULL)
47: {
48: struct exit_function_list *cur = *listp;
49:
50: while (cur->idx > 0)
51: {
52: const struct exit_function *const f =
53: &cur->fns[--cur->idx];
54: switch (f->flavor)
55: {
56: void (*atfct) (void);
57: void (*onfct) (int status, void *arg);
58: void (*cxafct) (void *arg, int status);
...
77: case ef_cxa:
78: cxafct = f->func.cxa.fn;
79:#ifdef PTR_DEMANGLE
80: PTR_DEMANGLE (cxafct);
81:#endif
82: cxafct (f->func.cxa.arg, status);
83: break;
84: }
...
97: _exit (status);
98:}
最後に_exit()が呼ばれていることが確認できる。
またwhile()でループしているのは、おそらくatexit()の処理だろう。atexit()により登録された関数が、ここで順次呼ばれていくわけだ。
atexit()のソースコードも見ておこう。man atexitではstdlib.hをインクルードするように書いてあるので、stdlibというディレクトリに本体がありそうだ。
見てみるとstdlib/atexit.cというファイルがある。そしてその中でatexit()は以下のように定義されている。
43:/* Register FUNC to be executed by `exit'. */
44:int
45:#ifndef atexit
46:attribute_hidden
47:#endif
48:atexit (void (*func) (void))
49:{
50: return __cxa_atexit ((void (*) (void *)) func, NULL,
51: &__dso_handle == NULL ? NULL : __dso_handle);
52:}
__cxa_atexit()という関数を呼んでいるようだ。これはどこにあるだろうか。
[user@localhost glibc-2.21]$ grep __cxa_atexit */* ... stdlib/cxa_atexit.c:__cxa_atexit (void (*func) (void *), void *arg, void *d) ...
stdlib/cxa_atexit.cを見ればいいようだ。
52:/* Register a function to be called by exit or when a shared library
53: is unloaded. This function is only called from code generated by
54: the C++ compiler. */
55:int
56:__cxa_atexit (void (*func) (void *), void *arg, void *d)
57:{
58: return __internal_atexit (func, arg, d, &__exit_funcs);
59:}
今度は_ _internal_atexit()が呼ばれている。そして_ _internal_atexit()は同一ファイル内で、以下のように定義されている。
30:int
31:attribute_hidden
32:__internal_atexit (void (*func) (void *), void *arg, void *d,
33: struct exit_function_list **listp)
34:{
35: struct exit_function *new = __new_exitfn (listp);
36:
37: if (new == NULL)
38: return -1;
39:
40:#ifdef PTR_MANGLE
41: PTR_MANGLE (func);
42:#endif
43: new->func.cxa.fn = (void (*) (void *, int)) func;
44: new->func.cxa.arg = arg;
45: new->func.cxa.dso_handle = d;
46: atomic_write_barrier ();
47: new->flavor = ef_cxa;
48: return 0;
49:}
第4引数で渡されるlistpに対して新たなエントリとして、第1引数で渡される関数を登録するようだ。呼び出し元の__cxa_atexit()を見ると、これには&__exit_funcsというアドレスが渡されている。これがatexit()の関数のリストだ。
もう一度「exit()の処理を読む」の項のexit()を見直してみよう。
__exit_funcsを第2引数にして、__run_exit_handlers()を呼んでいる。これが__run_exit_handlers()に渡され、登録された関数を順次実行しているわけだ。
ハロー“Hello, World” OSと標準ライブラリのシゴトとしくみ
坂井弘亮著
秀和システム 3,200円
C言語の入門書では、"Hello, World"と出力するプログラムを最初に作るのが定番です。"Hello, World"は、たった7行の単純なプログラムですが、printf()の先では何が行われているのか、main()の前にはいったい何があるのか、考えてみると謎だらけです。本書は、基礎中の基礎である"Hello, World"プログラムを元に、OSと標準ライブラリの仕組みをあらゆる角度からとことん解析します。資料に頼らず、自分の手で調べる方法がわかります。
プログラミング言語Cについて知ろう
シェルコード解析に必携の「5つ道具」
【 od 】コマンド――ファイルを8進数や16進数でダンプするCopyright © ITmedia, Inc. All Rights Reserved.