glibcを使わないでHello Worldを書く。FreeBSD版その2
この記事は、d:id:SumiTomohiko:20061221:1166685804の続きです。
概要
通常のHello Worldとlibcを使用しないHello Worldの2つについて、ktraceとkdumpを使用してシステムコールの呼び出しを追跡します。
結果
通常のHello Worldを実行すると、mmapやread, openといった様々なシステムコールが呼び出されます。libcを使用しないHello Worldを実行しても、writeとexitしか呼び出されません。
詳細
Linuxでは、straceを用いればシステムコールの呼び出しを追跡することができます。FreeBSDでは、これはktraceとkdumpを用います。
まずはじめに、ktraceで追跡する対象のコマンドを実行します。そうすると、ログが(標準では)ktrace.outというファイルに出力されます。このファイルは人には読めないので、読むときはkdumpを使用します。
では、標準のHello Worldに対してktraceをしてみます。これは、以下のようになります。
$ ktrace ./hello [~/projects/standard_hello] Hello, world! $ kdump [~/projects/standard_hello] 4427 ktrace RET ktrace 0 4427 ktrace CALL execve(0xbfbfed77,0xbfbfeca4,0xbfbfecac) 4427 ktrace NAMI "./hello" 4427 ktrace NAMI "/libexec/ld-elf.so.1" 4427 hello RET execve 0 4427 hello CALL mmap(0,0xe18,0x3,0x1000,0xffffffff,0,0,0) 4427 hello RET mmap 671531008/0x2806c000 4427 hello CALL munmap(0x2806c000,0xe18) 4427 hello RET munmap 0 4427 hello CALL __sysctl(0xbfbfea48,0x2,0x28068998,0xbfbfea44,0,0) 4427 hello RET __sysctl 0 4427 hello CALL mmap(0,0x8000,0x3,0x1002,0xffffffff,0,0,0) 4427 hello RET mmap 671531008/0x2806c000 4427 hello CALL issetugid 4427 hello RET issetugid 0 4427 hello CALL open(0x28064c28,0,0x1b6) 4427 hello NAMI "/etc/libmap.conf" 4427 hello RET open -1 errno 2 No such file or directory 4427 hello CALL open(0x28063e80,0,0) 4427 hello NAMI "/var/run/ld-elf.so.hints" 4427 hello RET open 3 4427 hello CALL read(0x3,0xbfbfea10,0x80) 4427 hello GIO fd 3 read 128 bytes 0x0000 4568 6e74 0100 0000 8000 0000 5100 0000 |Ehnt........Q...| 0x0010 0000 0000 5000 0000 0000 0000 0000 0000 |....P...........| 0x0020 0000 0000 0000 0000 0000 0000 0000 0000 |................| (略) 0x0050 0000 0000 0000 0000 0000 0000 0000 0000 |................| 0x0060 0000 0000 0000 0000 0000 0000 0000 0000 |................| 0x0070 0000 0000 0000 0000 0000 0000 0000 0000 |................| 4427 hello RET read 128/0x80 4427 hello CALL lseek(0x3,0,0x80,0,0) 4427 hello RET lseek 128/0x80 4427 hello CALL read(0x3,0x28070000,0x51) 4427 hello GIO fd 3 read 81 bytes "/lib:/usr/lib:/usr/lib/compat:/usr/X11R6/lib:/usr/local/lib:/usr/local\ /lib/mysql\0" 4427 hello RET read 81/0x51 4427 hello CALL close(0x3) 4427 hello RET close 0 4427 hello CALL access(0x28071000,0) 4427 hello NAMI "/lib/libc.so.6" 4427 hello RET access 0 4427 hello CALL open(0x2806d020,0,0) 4427 hello NAMI "/lib/libc.so.6" 4427 hello RET open 3 4427 hello CALL fstat(0x3,0xbfbfea50) 4427 hello RET fstat 0 4427 hello CALL read(0x3,0x280678e0,0x1000) 4427 hello GIO fd 3 read 4096 bytes 0x0000 7f45 4c46 0101 0109 0000 0000 0000 0000 |.ELF............| 0x0010 0300 0300 0100 0000 50d9 0100 3400 0000 |........P...4...| 0x0020 1471 0d00 0000 0000 3400 2000 0300 2800 |.q......4. ...(.| (略) 0x0fd0 0e04 0000 8f0a 0000 0000 0000 4108 0000 |............A...| 0x0fe0 0000 0000 670a 0000 6a04 0000 0000 0000 |....g...j.......| 0x0ff0 e508 0000 0000 0000 0000 0000 7403 0000 |............t...| 4427 hello RET read 4096/0x1000 4427 hello CALL mmap(0,0xd8000,0x5,0x20002,0x3,0,0,0) 4427 hello RET mmap 671563776/0x28074000 4427 hello CALL mprotect(0x28133000,0x1000,0x7) 4427 hello RET mprotect 0 4427 hello CALL mprotect(0x28133000,0x1000,0x5) 4427 hello RET mprotect 0 4427 hello CALL mmap(0x28134000,0x5000,0x3,0x12,0x3,0,0xc0000,0) 4427 hello RET mmap 672350208/0x28134000 4427 hello CALL mmap(0x28139000,0x13000,0x3,0x1012,0xffffffff,0,0,0) 4427 hello RET mmap 672370688/0x28139000 4427 hello CALL close(0x3) 4427 hello RET close 0 4427 hello CALL sysarch(0xa,0xbfbfeac0) 4427 hello RET sysarch 0 4427 hello CALL mmap(0,0x88,0x3,0x1000,0xffffffff,0,0,0) 4427 hello RET mmap 672448512/0x2814c000 4427 hello CALL munmap(0x2814c000,0x88) 4427 hello RET munmap 0 4427 hello CALL mprotect(0x28074000,0xc0000,0x7) 4427 hello RET mprotect 0 4427 hello CALL mmap(0,0x56c0,0x3,0x1000,0xffffffff,0,0,0) 4427 hello RET mmap 672448512/0x2814c000 4427 hello CALL munmap(0x2814c000,0x56c0) 4427 hello RET munmap 0 4427 hello CALL mprotect(0x28074000,0xc0000,0x5) 4427 hello RET mprotect 0 4427 hello CALL sigprocmask(0x1,0x28067820,0xbfbfea90) 4427 hello RET sigprocmask 0 4427 hello CALL sigprocmask(0x3,0x28067830,0) 4427 hello RET sigprocmask 0 4427 hello CALL fstat(0x1,0xbfbfe460) 4427 hello RET fstat 0 4427 hello CALL readlink(0x2812d47b,0xbfbfe480,0x3f) 4427 hello NAMI "/etc/malloc.conf" 4427 hello RET readlink -1 errno 2 No such file or directory 4427 hello CALL issetugid 4427 hello RET issetugid 0 4427 hello CALL mmap(0,0x1000,0x3,0x1002,0xffffffff,0,0,0) 4427 hello RET mmap 672448512/0x2814c000 4427 hello CALL break(0x804b000) 4427 hello RET break 0 4427 hello CALL break(0x804c000) 4427 hello RET break 0 4427 hello CALL ioctl(0x1,TIOCGETA,0xbfbfe4a0) 4427 hello RET ioctl 0 4427 hello CALL write(0x1,0x804b000,0xe) 4427 hello GIO fd 1 wrote 14 bytes "Hello, world! " 4427 hello RET write 14/0xe 4427 hello CALL exit(0)
単に"Hello, world!"と表示するだけであっても、ファイルを読み込んだりシグナルの設定をしたりしているのが分かると思います。
では次に、libcを使用しないHello Worldの動作を追跡してみます。
$ ktrace ./hello [~/projects/minimum_hello-1.0] Hello, world! $ kdump [~/projects/minimum_hello-1.0] 7357 ktrace RET ktrace 0 7357 ktrace CALL execve(0xbfbfed8f,0xbfbfecbc,0xbfbfecc4) 7357 ktrace NAMI "./hello" 7357 hello RET execve 0 7357 hello CALL write(0x1,0x80480d2,0xe) 7357 hello GIO fd 1 wrote 14 bytes "Hello, world! " 7357 hello RET write 14/0xe 7357 hello CALL exit(0)
標準のHello Worldに比べ、たいへん短くなっています。helloコマンドが動作してから後は、writeとexitしか呼ばれていません。そうなるように作ったから当然なのですが、狙い通りにできているのがktraceの結果からも確認できます。