はじめに
共有ライブラリについて簡単にまとめてみました
共有ライブラリとは
- 共有ライブラリとは、部品化されたプログラムの集合であるライブラリの一種で、複数のプログラムから共有・共用されるもの。
- C言語でmain関数の中を空にしてもスタートアッププログラムがリンクされる。
- UNIX系のOSでは「.so.(バージョン番号)」という拡張子のファイルとして、また、Windowsの場合は「. DLL」という拡張子のファイルとして提供される。
実行形式の共有ライブラリの確認
ldd a.out
linux-gate.so.1 => (0xb776e000)
libc.so.6 => /lib/libc.so.6 (0x49cbd000)
/lib/ld-linux.so.2 (0x49c95000)
- .soフアイルが共有ファイル
共有ファイルの仕組み
仮想メモリ
- 共有ライブラリは物理メモリに1つ存在していて、複数のプログラムから共有される
- 各プロセスは各々で仮想メモリ空間に共有ライブラリがロードされる。その時の共有ライブラリは各プロセスでメモリ番地が異なる
動的リンク
- 共有ライブラリはプログラム実行時に動的にリンクされる。それまでは共有ライブラリの関数などの番地は空欄?
共有ライブラリのシンボル解決
共有ライブラリは各プロセスで共有されて、各プロセスの仮想メモリにはそれぞれ別のメモリ番地に割り当てられる。さらに共有ライブラリは実行時にリンクされるので実行時までメモリ番地が決定されない。よってプログラムの実行時には共有ライブラリの参照箇所はシンボル解決が行われていな。なので、実行時には決定されていない共有ライブラリのメモリ番地を調べてシンボル解決する仕組みが必要になる。それがGOTとPLT。
位置独立コード
- GOT、PLTの仕組みから成る主記憶装置内のどこに置かれても絶対アドレスに関わらず正しく実行できる仕組みのこと。共有ライブラリがその仕組を利用している。
- 各プログラムが(例えば他の共有ライブラリに)使われていない任意の別々のアドレスに同じ共有ライブラリをロードして使うことができるようになる。
GOT、PLTその前に
- 共有ライブラリは実体は物理メモリに一つあるのみで、各プロセスから共有されている。各プロセスでは各々で仮想空間上の異なるメモリ番地に共有ライブラリをマッピングしている。よって、各プロセスでロードしているメモリ番地が異なるので、共有ライブラリの関数などを使用する際のメモリ番地を決定することはできない。そこでGOTとPLTを用いてメモリ番地を決定している。
- GOTとPLTは各プロセスが各々で保持している
GOTとPLTの流れ
- 実行ファイルから共有ライブラリの関数を実行。例えばpfintfを使用する場合、アセンブラで見るとprintf@pltとなっている
- まず、pltセグメントに処理が飛ぶ。初回はシンボル解決して解決した関数の番地をGOTに埋め込む
- 2回目のアクセスもpltセグメントに飛ぶ。2回目はGOTに飛ぶ処理になり、目的の関数がGOTにすでに埋め込まれているので目的の関数が実行される
GOT
- 直接共有ライブラリへ参照はせず、GOT領域を使用する。GOTはデータ領域に配置されるので各プロセスが独自に持てる領域。なので各プロセスはここで各々プロセスによって異なる共有ライブラリへの参照を保持する。
- 初期値はその共有ライブラリへのシンボル解決するメモリ番地への値が入っていてシンボル解決するとこの各共有ライブラリの関数などに対応するGOT領域にアクセスすれば共有ライブラリに参照ができる。
PLT
- PLTは対象の共有ライブラリへ参照するためにGOTに飛ぶ。PLT→GOT→共有ライブラリ