動的ライブラリの観察その1
今回からは動的ライブラリが利用される様子を観察してみる。
ライブラリとは
リンク可能なオブジェクトファイルの集まり。ライブラリには静的ライブラリと動的ライブラリが有る。
静的ライブラリ
- 実行形式ファイルには必要なコードが全てコピーされる
- 実行形式ファイルのサイズは大きくなり起動時間は長い
- 実行形式ファイルの占有メモリ容量は大きい
- ライブラリに修正が加えられても再度コンパイルしなければ実行形式ファイルには反映されない
- 他のファイルに依存すること無く実行形式ファイル単体で実行可能
動的ライブラリ
- 実行形式ファイルにはどのライブラリを利用するかという情報だけが記録される
- 必要なライブラリは起動時にメモリに読み込まれる
- 実行時に動的に読み込むことも可能
- 実行形式ファイルのサイズは小さく起動時間は早い
- 実行形式ファイルの占有メモリ容量は小さい。
- ライブラリに修正が加えられれば実行形式は変更しなくても反映される
- 必要なライブラリが存在しなければ実行できない
ちなみに、Mac OS X ではユーザーバイナリの静的リンクはサポートしていない。(Static linking of user binaries on Mac OS X)
実際の動的ライブラリで観察
まずはプロセスのアドレス空間のどの辺りに読み込まれるのかを見てみる。
単純な動的ラブラリを作る。
$ cat libhoge4.c int do_hoge(int i) { return i; }
$ gcc --save-temps -dynamiclib -o libhoge4.dylib libhoge4.c $ file libhoge4.dylib libhoge4.dylib: Mach-O 64-bit dynamically linked shared library x86_64
動的ライブラリを利用するコード
$ cat hoge4.c #include <unistd.h> #include <stdio.h> int do_hoge(int); int main(int argc, char **argv) { do_hoge(5); do_hoge(6); puts("asdf\n"); }
$ gcc --save-temps -L./ -lhoge4 -o hoge4 hoge4.c $ otool -L hoge4 hoge4: libhoge4.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.0)
otoolコマンドでリンクされている動的ライブラリの一覧を表示することができる。hoge4が先程作った動的ライブラリとリンクされていることがわかる。
gdbで実行。メイン関数から戻る辺りで止めておく。
$ gdb hoge4 (gdb) disas main Dump of assembler code for function main: 0x0000000100000ee8: push %rbp 0x0000000100000ee9 : mov %rsp,%rbp 0x0000000100000eec : sub $0x10,%rsp 0x0000000100000ef0 : mov %edi,-0x4(%rbp) 0x0000000100000ef3 : mov %rsi,-0x10(%rbp) 0x0000000100000ef7 : mov $0x5,%edi 0x0000000100000efc : callq 0x100000f1a 0x0000000100000f01 : mov $0x6,%edi 0x0000000100000f06 : callq 0x100000f1a 0x0000000100000f0b : lea 0x48(%rip),%rdi # 0x100000f5a 0x0000000100000f12 : callq 0x100000f26 0x0000000100000f17 : leaveq 0x0000000100000f18 : retq End of assembler dump. (gdb) b *0x0000000100000f18 Breakpoint 1 at 0x100000f18 (gdb) run Starting program: hoge4 Reading symbols for shared libraries ++. done asdf Breakpoint 1, 0x0000000100000f18 in main () (gdb)
vmmapコマンドで仮想アドレス空間のレイアウトを表示する。これにはどのファイルの内容がどのアドレス範囲に読み込まれているかや、そのアドレス範囲の属性(読込可否、書込実可否、実行可否、共有モードetc)が含まれている。ちなみに、Linuxでも cat /proc/<プロセスID>/maps とすればよく似た情報を得ることができる。
$ ps | grep hoge4 89976 s004 S+ 0:00.07 /usr/libexec/gdb/gdb-i386-apple-darwin hoge4 89987 s004 SX 0:00.01 hoge4 89998 s005 S+ 0:00.00 grep hoge4 $ vmmap -interleaved 89987 ← hoge4 のプロセスID Virtual Memory Map of process 89987 (hoge4) Output report format: 2.2 -- 64-bit process ==== regions for process 89987 (non-writable and writable regions are interleaved) __TEXT 0000000100000000-0000000100001000 [ 4K] r-x/rwx SM=COW hoge4 __DATA 0000000100001000-0000000100002000 [ 4K] rw-/rwx SM=PRV hoge4 __LINKEDIT 0000000100002000-0000000100003000 [ 4K] r--/rwx SM=COW hoge4 __TEXT 0000000100003000-0000000100004000 [ 4K] r-x/rwx SM=COW libhoge4.dylib __LINKEDIT 0000000100004000-0000000100005000 [ 4K] r--/rwx SM=COW libhoge4.dylib STACK GUARD 0000000100005000-0000000100006000 [ 4K] ---/rwx SM=NUL MALLOC (admin) 0000000100006000-0000000100007000 [ 4K] rw-/rwx SM=COW STACK GUARD 0000000100007000-0000000100009000 [ 8K] ---/rwx SM=NUL MALLOC (admin) 0000000100009000-0000000100014000 [ 44K] rw-/rwx SM=COW STACK GUARD 0000000100014000-0000000100016000 [ 8K] ---/rwx SM=NUL MALLOC (admin) 0000000100016000-0000000100021000 [ 44K] rw-/rwx SM=COW STACK GUARD 0000000100021000-0000000100022000 [ 4K] ---/rwx SM=NUL MALLOC (admin) 0000000100022000-0000000100023000 [ 4K] r--/rwx SM=COW MALLOC_TINY 0000000100100000-0000000100200000 [ 1024K] rw-/rwx SM=COW DefaultMallocZone_0x100006000 MALLOC_SMALL 0000000100800000-0000000101000000 [ 8192K] rw-/rwx SM=COW DefaultMallocZone_0x100006000 STACK GUARD 00007fff5bc00000-00007fff5f400000 [ 56.0M] ---/rwx SM=NUL Stack 00007fff5f400000-00007fff5fbfd000 [ 8180K] rw-/rwx SM=ZER Stack 00007fff5fbfd000-00007fff5fbfe000 [ 4K] rw-/rwx SM=PRV Stack 00007fff5fbfe000-00007fff5fbff000 [ 4K] rw-/rwx SM=ZER Stack 00007fff5fbff000-00007fff5fc00000 [ 4K] rw-/rwx SM=COW thread 0 __TEXT 00007fff5fc00000-00007fff5fc0a000 [ 40K] r-x/rwx SM=COW /usr/lib/dyld __TEXT 00007fff5fc0a000-00007fff5fc0b000 [ 4K] r-x/rwx SM=PRV /usr/lib/dyld __TEXT 00007fff5fc0b000-00007fff5fc3c000 [ 196K] r-x/rwx SM=COW /usr/lib/dyld __DATA 00007fff5fc3c000-00007fff5fc41000 [ 20K] rw-/rwx SM=COW /usr/lib/dyld __DATA 00007fff5fc41000-00007fff5fc43000 [ 8K] rw-/rwx SM=ZER /usr/lib/dyld __DATA 00007fff5fc43000-00007fff5fc44000 [ 4K] rw-/rwx SM=COW /usr/lib/dyld __DATA 00007fff5fc44000-00007fff5fc7b000 [ 220K] rw-/rwx SM=ZER /usr/lib/dyld __LINKEDIT 00007fff5fc7b000-00007fff5fc8f000 [ 80K] r--/rwx SM=COW /usr/lib/dyld __DATA 00007fff70b60000-00007fff70b83000 [ 140K] rw-/rwx SM=COW /usr/lib/libSystem.B.dylib __TEXT 00007fff864f3000-00007fff866b2000 [ 1788K] r-x/r-x SM=COW /usr/lib/libSystem.B.dylib __TEXT 00007fff86780000-00007fff86785000 [ 20K] r-x/r-x SM=COW /usr/lib/system/libmathCommon.A.dylib __LINKEDIT 00007fff86f3b000-00007fff88439000 [ 21.0M] r--/r-- SM=COW /usr/lib/system/libmathCommon.A.dylib ==== Legend SM=sharing mode: COW=copy_on_write PRV=private NUL=empty ALI=aliased SHM=shared ZER=zero_filled S/A=shared_alias
libhoge4.dylib が hoge4 のすぐ上にロードされている。libSystem.B.dylib はずいぶん上の端にロードされている。libmathCommon.A.dylibというのは・・・・
$ otool -L /usr/lib/libSystem.B.dylib /usr/lib/libSystem.B.dylib: /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.0) /usr/lib/system/libmathCommon.A.dylib (compatibility version 1.0.0, current version 315.0.0)
libSystem.B.dylibが依存しているライブラリか。dyldというのはダイナミックローダー。これが実行形式ファイルや各動的ライブラリをロードしてくれる。
それにしても上の図とはライブラリの配置がずいぶん違っているな。"共有メモリ"という仕組みの関係でこう成っているのかもしれない。そのうち調べよう。
上の結果にさらに otool -l で得たセクションの情報も合わせてみるとこうなる。
__TEXT 0000000100000000-0000000100001000 [ 4K] r-x/rwx SM=COW hoge4 sectname __text segname __TEXT addr 0x0000000100000eac size 0x000000000000006d sectname __symbol_stub1 segname __TEXT addr 0x0000000100000f1a size 0x0000000000000012 sectname __stub_helper segname __TEXT addr 0x0000000100000f2c size 0x000000000000002e sectname __cstring segname __TEXT addr 0x0000000100000f5a size 0x0000000000000006 sectname __unwind_info segname __TEXT addr 0x0000000100000f60 size 0x0000000000000054 sectname __eh_frame segname __TEXT addr 0x0000000100000fb8 size 0x0000000000000048 __DATA 0000000100001000-0000000100002000 [ 4K] rw-/rwx SM=COW hoge4 sectname __nl_symbol_ptr segname __DATA addr 0x0000000100001000 size 0x0000000000000010 sectname __la_symbol_ptr segname __DATA addr 0x0000000100001010 size 0x0000000000000018 sectname __program_vars segname __DATA addr 0x0000000100001040 size 0x0000000000000028 sectname __data segname __DATA addr 0x0000000100001068 size 0x0000000000000020 __LINKEDIT 0000000100002000-0000000100003000 [ 4K] r--/rwx SM=COW hoge4 __TEXT 0000000100003000-0000000100004000 [ 4K] r-x/rwx SM=COW libhoge4.dylib __LINKEDIT 0000000100004000-0000000100005000 [ 4K] r--/rwx SM=COW libhoge4.dylib STACK GUARD 0000000100005000-0000000100006000 [ 4K] ---/rwx SM=NUL MALLOC (admin) 0000000100006000-0000000100007000 [ 4K] rw-/rwx SM=COW STACK GUARD 0000000100007000-0000000100009000 [ 8K] ---/rwx SM=NUL MALLOC (admin) 0000000100009000-0000000100014000 [ 44K] rw-/rwx SM=COW STACK GUARD 0000000100014000-0000000100016000 [ 8K] ---/rwx SM=NUL MALLOC (admin) 0000000100016000-0000000100021000 [ 44K] rw-/rwx SM=PRV STACK GUARD 0000000100021000-0000000100022000 [ 4K] ---/rwx SM=NUL MALLOC (admin) 0000000100022000-0000000100023000 [ 4K] r--/rwx SM=COW MALLOC_TINY 0000000100100000-0000000100200000 [ 1024K] rw-/rwx SM=COW DefaultMallocZone_0x100006000 STACK GUARD 00007fff5bc00000-00007fff5f400000 [ 56.0M] ---/rwx SM=NUL Stack 00007fff5f400000-00007fff5fbfd000 [ 8180K] rw-/rwx SM=ZER Stack 00007fff5fbfd000-00007fff5fbfe000 [ 4K] rw-/rwx SM=PRV Stack 00007fff5fbfe000-00007fff5fbff000 [ 4K] rw-/rwx SM=ZER Stack 00007fff5fbff000-00007fff5fc00000 [ 4K] rw-/rwx SM=COW thread 0 __TEXT 00007fff5fc00000-00007fff5fc0a000 [ 40K] r-x/rwx SM=COW /usr/lib/dyld __TEXT 00007fff5fc0a000-00007fff5fc0b000 [ 4K] r-x/rwx SM=PRV /usr/lib/dyld __TEXT 00007fff5fc0b000-00007fff5fc16000 [ 44K] r-x/rwx SM=COW /usr/lib/dyld __TEXT 00007fff5fc16000-00007fff5fc17000 [ 4K] r-x/rwx SM=PRV /usr/lib/dyld __TEXT 00007fff5fc17000-00007fff5fc3c000 [ 148K] r-x/rwx SM=COW /usr/lib/dyld __DATA 00007fff5fc3c000-00007fff5fc41000 [ 20K] rw-/rwx SM=COW /usr/lib/dyld __DATA 00007fff5fc41000-00007fff5fc43000 [ 8K] rw-/rwx SM=ZER /usr/lib/dyld __DATA 00007fff5fc43000-00007fff5fc44000 [ 4K] rw-/rwx SM=COW /usr/lib/dyld __DATA 00007fff5fc44000-00007fff5fc7b000 [ 220K] rw-/rwx SM=ZER /usr/lib/dyld __LINKEDIT 00007fff5fc7b000-00007fff5fc8f000 [ 80K] r--/rwx SM=COW /usr/lib/dyld __DATA 00007fff70b60000-00007fff70ba0000 [ 256K] rw-/rwx SM=COW /usr/lib/libSystem.B.dylib __TEXT 00007fff864f3000-00007fff865fb000 [ 1056K] r-x/r-x SM=COW /usr/lib/libSystem.B.dylib __TEXT 00007fff865fb000-00007fff865fc000 [ 4K] r-x/rwx SM=COW /usr/lib/libSystem.B.dylib __TEXT 00007fff865fb000-00007fff86780000 [ 1556K] r-x/r-x SM=COW /usr/lib/libSystem.B.dylib __TEXT 00007fff86780000-00007fff86785000 [ 20K] r-x/r-x SM=COW /usr/lib/system/libmathCommon.A.dylib __TEXT 00007fff86785000-00007fff867ba000 [ 212K] r-x/r-x SM=COW /usr/lib/libSystem.B.dylib __LINKEDIT 00007fff86f3b000-00007fff88439000 [ 21.0M] r--/r-- SM=COW /usr/lib/system/libmathCommon.A.dylib
まとめ
- 動的ライブラリを利用する実行形式ファイルが実行されている時の具体的なメモリレイアウトを確認した