次にある「Export Name Pointer Table」は、関数の名前となる文字列を保存している「Export Name Table」内の、各関数名の先頭位置を表にしたものだ。これを順番に見ていけば、関数の名前をすべて得られる。
最後の「Export Ordinal Number Table」は、Export Name Tableと対になっていて、同じ位置にある関数名に対応する序数を保存してある。これを使うことで、名前から序数が得られる。
関数が名前で指定されている場合、WindowsはExport Name Pointer Tableの要素が指し示す、Export Name Table内の文字列をひとつひとつ照合していく。n番目の要素が一致したら、Export Ordinal Number Tableからn番目の要素を取り出す。これが序数となる。一方Export Address TableのX番目の要素は、序数Xに対応しているため、序数がわかればExport Address Tableを見て、関数の開始アドレスを得られるわけだ。
バージョンアップでDLLが変わったらどうなる?
APIの呼び出し先としてDLLを見た場合、Windowsのバージョンが変わっても、同じDLL名や関数名(または序数)でアクセスできなければならない。しかしそうなると、DLLの変更は困難になる。「序数が変わったら今までのアプリケーションからはアクセスできなくなりました」では困るわけだ。
そのためDLLには、「フォワード」という機構がある(図2)。これは、Export Address Tableが指すアドレスが関数の開始位置ではなく、ほかのDLLの名前と関数名(または序数)を表した文字列になっている。この場合、Windowsは、アドレスが実行コードのセクションにあるのか、そうでないのかを見て、飛び先が関数なのか、ほかのDLL名なのかを判断する。
Export Address Table内のアドレスがコードセクションではなかった場合、Windowsは、これを「次のDLLの名前と関数名(を表す文字列)」だと解釈する。こうしておけば、例えばOSカーネル内部の関数名などが変わっても、アプリケーションから見えるDLL名や関数名を、一定にしておくことができる。
なお、メモリー内にDLLが読み込まれると、各関数の開始アドレスが確定する。OSカーネルはこのときに、関数のアドレスを記録しておく。呼び出し側はOSが記録したアドレスを受け取って、関数を呼び出す形となる。フォワードの場合には、転送先のDLLもメモリーに読み込まれて各関数のアドレスが確定するので、これが呼び出し側に渡される。この部分は、EXEファイルのインポートセクションが関係しているが、今回のテーマとは外れるので割愛する。
この連載の記事
-
第12回
PC
アプリがWindowsの機能を使うには? APIとDLLの仕組み -
第11回
PC
マルチコアCPUの消費電力はスケジューリングで変わる? -
第10回
PC
AMD FX向けにパッチで修正 スケジューラーが抱える難題 -
第9回
PC
マルチコアCPUを賢く使いこなす スケジューリングの秘密 -
第8回
PC
意味の違いがわかる? タスクとプロセスとスレッド -
第7回
PC
Windowsのメモリー管理をx86の仕組みから読み解く -
第6回
PC
メモリー不足を根本的に解決する64bit OSの仕組み -
第5回
PC
Windows 8でMetro Styleアプリを動かす「WinRT」 -
第4回
PC
Windowsを動かすデバイスドライバーの仕組み 前編 -
第3回
PC
OSの仕事はハードウェアをアプリから「隠す」こと? - この連載の一覧へ