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の結果からも確認できます。