組込みエンジニアのためのLinux入門 ダイナミックリンク編(3) 2007.8.31 株式会社アプリックス 小林哲之 1 このスライドの対象とする方 • 今までずっと組込み機器のプロジェクト に携わってきて最近はOSにLinuxを使っ ている方々 2 このスライドの目的 • Linuxで使用されているダイナミックリン クの仕組みを理解し現在のプロジェクト に役立てる。 – 仕組みを知らなくてもプログラムは動くが、 トラブルに対処したり性能を引き出すため には仕組みの理解が重要。 3 今日のお題 • 共有ライブラリの簡単な歴史 • Prelinkとは • Prelinkのtips 4 共有ライブラリの簡単な歴史 • a.out時代 • ELF時代 • ELF + prelink 5 a.out 時代 • a.outはLinuxの最初のオブジェクトフォーマット。 • 共有ライブラリのリンクは静的に行う。 • ライブラリの配置アドレスは人手によって管理されて いた。 – ライブラリの更新でサイズが変わると大変。 – 世の中の全てのライブラリを重ならないように配置しよう とするとアドレス空間が足りなくなる! • ライブラリの作成も大変。 • 起動時の処理はシンプルなので速い。 6 ELF時代 • ELFはダイナミックリンクが簡単にできるよう に考慮されたオブジェクトフォーマット • ダイナミックリンク – ライブラリの配置アドレスは起動時に決定 • ライブラリのアドレスの集中管理が不要になった • ライブラリの作成も簡単になった – 起動時にリンクを行う • 起動時のオーバーヘッドが大きくなった 7 ELF + prelink a.out ELF ELF + prelink ライブラリの作成、管理 大変 ラク ラク 起動時のオーバーヘッド 小 大 小 PrelinkはELFのライブラリの作成、管理の容易さを保ったまま 起動時のオーバーヘッド削減を目指す 8 Prelinkとは • 通常は起動時に行われるリンクの処理を、 あらかじめ済ませておくことにより起動時間の 短縮をねらう。 • CELFテクニカルジャンボリーでもたびたび紹 介され、起動時間短縮の効果が実証されて いる。 9 CELFでのprelinkの紹介 • テクニカルジャンボリー #3 (2005.7) – “携帯電話にLinuxを実装する!” – シンボルの解決にかかる時間が2479msec →125msec • テクニカルジャンボリー#9 (2006.7) – “NECによる携帯電話向けリナックスの改良” • テクニカルジャンボリー #13 (2007.2) – “Evaluation of MIPS pre-link” • Prelinkのまとめページ – http://tree.celinuxforum.org/CelfPubWiki/PreLinking 10 Prelinkは実際に何をやってくれるのか • ダイナミックリンクライブラリは起動時に配置アドレ スが決まるので、その後のシンボルの解決等の ローダの処理の負荷が大きかった。 • Prelinkでは – 全てのダイナミックリンクライブラリを走査して配置するア ドレスを決定する。 – それぞれのダイナミックリンクライブラリのロードアドレス を決定したアドレスにセットする. – 依存関係のある実行ファイル、ダイナミックリンクライブラ リのアドレス参照を解決する。 • これによりローダの起動時の処理が大幅に軽減さ れた。 11 prelinkの使用法 $ prelink -avR -a /etc/prelink.conf に指定してあるディレクトリのダイナミックリンクライブラリと 実行ファイルのprelinkを行う -v vorbose -R アドレスをランダムに決める (ウィルス耐性が高まる) $ prelink <filename> 追加で指定されたファイルのprelinkを行う 12 /etc/prelink.cache 各ライブラリのアドレスと依存関係がバイナリフォーマットで格納される。 prelink –p で確認することができる。 # prelink -p 152 objects found in prelink cache `/etc/prelink.cache' /usr/lib/libwwwfile.so.0.1.0 [0x41eeda3e] 0x4a588000-0x4a597dec: /lib/tls/libdl-2.3.3.so [0x536dae10] /lib/tls/libc-2.3.3.so [0xedb6e392] /lib/ld-2.3.3.so [0x040c82cc] /usr/lib/libsctp.so.1.0.2 [0x26ac5ae2] 0x4adc8000-0x4add12ac: /lib/tls/libc-2.3.3.so [0xedb6e392] /lib/ld-2.3.3.so [0x040c82cc] /usr/lib/libreadline.so.4.3.old [0xf90fc4bc] 0x414180000x4144b770: /lib/tls/libc-2.3.3.so [0xedb6e392] /lib/ld-2.3.3.so [0x040c82cc] /usr/lib/libwwwnews.so.0.1.0 [0xdc63747e] 0x4ac78000-0x4ac86310: /lib/tls/libdl-2.3.3.so [0x536dae10] /lib/tls/libc-2.3.3.so [0xedb6e392] /lib/ld-2.3.3.so [0x040c82cc] .... 13 通常のライブラリ $ readelf -l libc-2.3.3.so Elf file type is DYN (Shared object file) Entry point 0x13708 There are 11 program headers, starting at offset 52 Program Headers: Type Offset EXIDX 0x0fbc3c PHDR 0x000034 INTERP 0x0fb410 [Requesting program LOAD 0x000000 LOAD 0x0fda64 DYNAMIC 0x0fef1c NOTE 0x000194 NOTE 0x0fdafc TLS 0x0fdae0 GNU_EH_FRAME 0x0fcf4c GNU_RELRO 0x0fda64 ロードアドレスが0 VirtAddr PhysAddr FileSiz MemSiz 0x000fbc3c 0x000fbc3c 0x01310 0x01310 0x00000034 0x00000034 0x00160 0x00160 0x000fb410 0x000fb410 0x00014 0x00014 interpreter: /lib/ld-linux.so.3] 0x00000000 0x00000000 0xfcf78 0xfcf78 0x00105a64 0x00105a64 0x02628 0x04da8 0x00106f1c 0x00106f1c 0x000e0 0x000e0 0x00000194 0x00000194 0x00020 0x00020 0x00105afc 0x00105afc 0x00074 0x00074 0x00105ae0 0x00105ae0 0x00008 0x00028 0x000fcf4c 0x000fcf4c 0x0002c 0x0002c 0x00105a64 0x00105a64 0x0159c 0x0159c Flg R R E R Align 0x4 0x4 0x4 R E RW RW R R R R R 0x8000 0x8000 0x4 0x4 0x4 0x4 0x4 0x1 14 prelinkしたライブラリ $ readelf -l libc-2.3.3.so Elf file type is DYN (Shared object file) Entry point 0x491c3708 There are 11 program headers, starting at offset 52 Program Headers: Type Offset EXIDX 0x0fbc3c PHDR 0x000034 INTERP 0x0fb410 [Requesting program LOAD 0x000000 LOAD 0x0fda64 DYNAMIC 0x0fef1c NOTE 0x000194 NOTE 0x0fdafc TLS 0x0fdae0 GNU_EH_FRAME 0x0fcf4c GNU_RELRO 0x0fda64 ロードアドレスが 割り当てられている VirtAddr PhysAddr FileSiz MemSiz 0x492abc3c 0x492abc3c 0x01310 0x01310 0x491b0034 0x491b0034 0x00160 0x00160 0x492ab410 0x492ab410 0x00014 0x00014 interpreter: /lib/ld-linux.so.3] 0x491b0000 0x491b0000 0xfcf78 0xfcf78 0x492b5a64 0x492b5a64 0x02628 0x04da8 0x492b6f1c 0x492b6f1c 0x000e0 0x000e0 0x491b0194 0x491b0194 0x00020 0x00020 0x492b5afc 0x492b5afc 0x00074 0x00074 0x492b5ae0 0x492b5ae0 0x00008 0x00028 0x492acf4c 0x492acf4c 0x0002c 0x0002c 0x492b5a64 0x492b5a64 0x0159c 0x0159c Flg R R E R Align 0x4 0x4 0x4 R E RW RW R R R R R 0x8000 0x8000 0x4 0x4 0x4 0x4 0x4 0x1 15 prelinkしたライブラリ # objdump -h libc-2.3.3.so libc-2.3.3.so: file format elf32-littlearm Sections: Idx Name Size VMA LMA File off Algn 0 .note.ABI-tag 00000020 491b0194 491b0194 00000194 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_CONTENTS 1 .hash 00002e74 491b01b4 491b01b4 000001b4 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA ... 69 .gnu_debuglink 00000018 00000000 00000000 001008f4 2**2 CONTENTS, READONLY 70 .gnu.liblist 00000014 00000000 00000000 0010090c 2**2 CONTENTS, READONLY 71 .gnu.libstr 00000014 00000000 00000000 00100920 2**0 CONTENTS, READONLY 72 .gnu.prelink_undo 00000cac 00000000 00000000 00100934 2**2 CONTENTS, READONLY # この3つのセクションが追加された。 その分だけファイルサイズ増加。 16 Prelinkによるファイルサイズの増加 size(bytes) prelinked size(bytes) delta delta% libc.so 1,054,936 1,058,384 3,448 0.326844 libm.so 432,088 433,792 1,704 0.394364 libcrypt.so 27,556 29,429 1,873 6.797068 libdl.so 15,036 16,900 1,864 12.39691 libX11.so 769,468 770,988 1,520 0.197539 libglib-2.0.so 557,908 559,508 1,600 0.286786 2,846,996 2,849,320 2,324 0.08163 bash 615,940 645,220 29,280 4.75371 busybox 622,640 627,596 4,956 0.795966 28,356 31,356 3,000 10.57977 libgtk-x11-2.0.so init 数KBの増加。 17 実行時のローダの動きを比較してみる • 環境変数 LD_DEBUG=all で実行すると ローダの実行ログが表示される。 • それをファイルに保存するためには LD_DEBUG_OUTPUT=<file name> • 統計情報のみ欲しい場合は LD_DEBUG=statistics 18 LD_DEBUG=allの例 # LD_DEBUG=all ./gtk_hello ....... 559: symbol=malloc; lookup in file=./gtk_hello 559: symbol=malloc; lookup in file=/usr/lib/libgtk-x11-2.0.so.0 559: symbol=malloc; lookup in file=/usr/lib/libgdk-x11-2.0.so.0 559: symbol=malloc; lookup in file=/usr/lib/libXrandr.so.2 559: symbol=malloc; lookup in file=/usr/lib/libXfixes.so.3 559: symbol=malloc; lookup in file=/usr/lib/libXcursor.so.1 559: symbol=malloc; lookup in file=/usr/lib/libatk-1.0.so.0 559: symbol=malloc; lookup in file=/usr/lib/libgdk_pixbuf-2.0.so.0 559: symbol=malloc; lookup in file=/usr/lib/libpangoxft-1.0.so.0 559: symbol=malloc; lookup in file=/usr/lib/libXft.so.2 559: symbol=malloc; lookup in file=/usr/lib/libXrender.so.1 559: symbol=malloc; lookup in file=/usr/lib/libXext.so.6 559: symbol=malloc; lookup in file=/usr/lib/libfontconfig.so.1 559: symbol=malloc; lookup in file=/usr/lib/libfreetype.so.6 559: symbol=malloc; lookup in file=/usr/lib/libz.so.1 559: symbol=malloc; lookup in file=/usr/lib/libpangox-1.0.so.0 559: symbol=malloc; lookup in file=/usr/lib/libX11.so.6 559: symbol=malloc; lookup in file=/usr/lib/libpango-1.0.so.0 559: symbol=malloc; lookup in file=/lib/tls/libm.so.6 559: symbol=malloc; lookup in file=/usr/lib/libgobject-2.0.so.0 559: symbol=malloc; lookup in file=/usr/lib/libgmodule-2.0.so.0 559: symbol=malloc; lookup in file=/lib/tls/libdl.so.2 559: symbol=malloc; lookup in file=/usr/lib/libglib-2.0.so.0 559: symbol=malloc; lookup in file=/lib/tls/libc.so.6 559: binding file /usr/lib/libexpat.so.0 to /lib/tls/libc.so.6: normal symbol `malloc' [GLIBC_2.4] ....... この例では全部で38000行 19 LD_DEBUG=statisticsの例 # LD_DEBUG=statistics ./gtk-hello 574: number of relocations: 574: number of relocations from cache: 574: number of relative relocations: 574: 574: runtime linker statistics: 574: final number of relocations: 574: final number of relocations from cache: 547 44 14309 1957 44 プロセスID 20 Prelinkの効果 prelink 無し number of relocations number of relocations from cache number of relative relocations runtime final number of relocations runtime final number of relocations from cache 全て prelink libのみ prelink 547 547 0 44 44 33 14309 0 0 1957 1957 56 44 44 33 テストプログラムは gtkで画面上にボタンを1個表示するもの。 21 実行時の物理メモリ消費量の比較 prelink 無し VmRSS (KBytes) 4300 libのみ prelink 4216 全て prelink 4164 -136KB テストプログラムは前頁と同じもの。 cat /proc/PID/status で観測した。 起動時のrelocationの処理が軽くなったのに伴って物理メモリ使用量も 減少している。 22 簡単なまとめ • プラス面 – 起動時間が短縮される – 実行時の物理メモリ消費量も少なくて済む • マイナス面 – ルートファイルシステム構築時に1工程増える – ファイルサイズが少し増加する 大抵のケースではプラス面が勝るであろう。 23 Prelinkの柔軟性 • prelinkされていないライブラリが混じってし まっても起動時間は最適でないけれども実行 はできる。このため致命的な問題が起こりにく い。 • prelinkしたライブラリを元に戻すこともできる。 (undoのための情報を保持している。この情 報の削除に関して後述) 24 PrelinkのTips • stripしてからprelinkするほうがファイルサイ ズが小さくなる。 • undo情報を削除してファイルサイズを減らそ うと試みた(しかしうまくいかなかった。) 25 ビルド手順へのprelinkの組込み • stripしてからprelinkするほうがファイルサイ ズが小さくなる。 strip size: 6,508 prelink 元の実行ファイル size: 9,452 こちらが小さい size: 10,511 prelink size: 13,699 strip size: 9,692 先にstripしたほうが、prelinkのときに付加されるundoのための情報の サイズが小さくて済むため 26 undo情報を削除してファイルサイズを 減らす • undo情報は起動時には使用されることが無 い。組込みの場合はundoすることはあまりな いと思われるため、undo情報は冗長? • objcopyコマンドかstripコマンドでundo情報 のセクションを削除する $ strip –remove-section=.gnu.prelink_undo <filename> これで減らせるファイルサイズは数百バイト~数キロバイト PCのLinux環境では問題がなかったが、手元にあったARMの環境では 実行ファイルでこれを行うと起動時にsegmentation faultになるものがあった。 ライブラリだけなら問題なかった。 27 参考文献 • “Prelink” http://people.redhat.com/jakub/prelink/prelink.pdf • “Linkers & Loaders” オーム社 • “BINARY HACKS” オライリージャパン • “GNU Development Tools” Wataru Nishida • GNU C ライブラリのソース http://www.gnu.org/software/libc/ • その他たくさんのWEB検索結果 28
© Copyright 2024 ExpyDoc