このページの本文へ

基礎から覚える 最新OSのアーキテクチャー 第13回

ARM版Windows 8実現の布石となったWindows 7の「MinWin」

2012年03月29日 12時00分更新

文● 塩田紳二

  • この記事をはてなブックマークに追加
  • 本文印刷

盲腸化したAPIを整理して実現した
Windows 7の「MinWin」

 Windows 7では、APIに対応するOS側のDLLを整理した。その理由のひとつには、GUIなしで立ち上がるOSの中核部分と、それ以外の部分を完全に分離したかったからだ。もうひとつの理由は、盲腸化したAPIへの対策だ。WindowsのAPIはこれまでの経緯から非常に多くなってきているため、今では利用が推奨されないにも関わらず、互換性維持のために残されているものも少なくない。こうした盲腸のような「古いAPI」が、新しいAPIと同じDLLに含まれていることも多い。

 現在でもAPIの互換性を保つために、アプリケーションから見えるDLL名や関数名は固定されている。API呼び出しは一回DLLで受けた後に、これを別のDLLに転送している。しかし現在のこの仕組みでは、APIを格納するDLLを変更すると、その転送先を記録しているAPIのDLLも変更する必要がある。またAPIを使ったり、DLLをファイルとして読み込んで解析すれば、この構造がどうなっているのかは簡単にわかってしまう。

 そこでWindows 7では、「Virtual DLL」という概念を取り入れた(図3)。まず現在のAPIを分類し、バージョン番号などをつけて整理する。見かけ上すべてのAPIは、カテゴリやバージョン番号を使って名前のDLLに転送する形をとる。しかし、実際には転送は行なわれず、別途用意されたデータベースでカテゴリやバージョンなどを参照し、適切なDLLへと転送するようになった。これにより、GUIなしで起動するのに必要なAPIと、そうでないAPIを分離できるようになった。

 この変更後も、当たり前だがアプリケーションがAPIを呼び出すときのやり方は、従来と変わらない。DLLを指定してその中の関数を呼び出すだけだ。これまではAPI用として定義されていた関数は、そのままWindowsのDLLの中にあったか、APIからは利用しない内部関数を呼び出すようになっていた。例えば「HeapAlloc」というアプリケーションがメモリーを確保する関数は、「Kernel32.DLL」が提供しているが、実際には、「NTDLL.DLL」内にある「RtlAllocHeap」という関数へと転送されていた。

図3 Virtual DLLはAPIを分類整理したカテゴリ名に対応する名称を持つ。APIを提供しているKernel32.DLLなどでは、その仮想DLLファイルへ転送されるように見える。しかし、DLLをロードするときにカーネルが内部に持つ情報を使い、APIを実装しているDLL内の関数のアドレスに書き換える。これにより、アプリケーション側からはAPIを実装しているDLLを見せずに、OS内部の構造を自由に変更することが可能になった

 Windows 7でも、アプリケーションからはこの関数が、Kernel32.DLLにあるように見えるのは同じである。ここは変えられない。だがKernel32.dllの中身を覗くと、HeapAllocという関数は「API-MS-WIN-CORE-HEAP-L1-1-0.DLL」というDLLに転送されているように見える。またこのDLLも、HeapAllocをエクスポートしている。しかし、このDLL内にあるHeapAllocという関数は、単にゼロを結果として戻すだけの、空の関数でしかない。

 実は重要な情報は、このDLL名と関数名を組み合わせた名前(API-MS-WIN-CORE-HEAP-L1-1-0.HeapAlloc)を使い、これと実際にコードがあるDLLの対応をデータベース化して、Windowsが管理している。具体的には、「ApiSetSchema.DLL」内に対応情報が格納されており、起動時にカーネルはこれを読み込む。

 DLLをメモリーに読み込むとき、カーネルは読み込んだ情報を使って、「DLL名.関数名」を実際のコードがあるDLLのアドレスに変換するようになっている。動作からいえば、前述の長いDLL名に対応するDLLファイルは不要なのだが、従来との互換性を保つためにファイルは用意されている。

 なおこの長いDLL名は、APIの分類名(MS-WIN-CORE-HEAP)、レイヤー(L1)、メジャーバージョン番号(1)、マイナーバージョン番号番号(0)の組み合わせとなっており、すべてのAPIがこの形で整理されている。

 APIを整理した目的のひとつは、GUIなしでの起動に必要な最小限のシステムファイルセット「MinWin」を作ることである。そのためには、必要なAPIとそうでないAPIを別のDLLに分離する必要がある。「KernelBase.DLL」はそのために新たに作られたDLLだ。前述のHeapAllocの場合、Kernel32.DLLはKernelBase.DLLにある関数を呼び出すように設定される。

 とはいえWindows 7でも、基本的な構造をまったく変えてしまったわけではない。OSのカーネル部分は長期間かけて細かいバグを取っていくものであり、そうそう簡単にゼロから作り直せるものでもない。特にカーネルが扱うようなAPIは、ちょっとした違いでアプリケーションに致命的なエラーを引き起こすことがあり、これまで多くのアプリケーションを動かしてきたコードだけが「信用」できるコードなのである。

 前述のHeapAllocという関数も、実体はKernelBase.DLLの中にはなく、「NTDLL.DLL」の中にある「RtlAllocHeap」という関数を呼び出す。しかし、この構造はアプリケーション側からは見えない。アプリケーション側からみると、前述の長い名前のDLLにHeapAllocという関数があって、それが動作しているようにしか見えないのである。

 KernelBase.DLLは、起動に必要な最低限のAPIを実現しているAPIセットを持つ。この中には、Kernel32.dllで提供されていた関数のほかに、「ADVAPI32.DLL」というDLLが持っていた関数も含む。これにより理論的には、GUIなしの最小単位でのOSが起動されたとしても、KernelBase.dllが提供しているAPIだけは確実に利用できる。

カテゴリートップへ

この連載の記事

注目ニュース

ASCII倶楽部

プレミアムPC試用レポート

ピックアップ

ASCII.jp RSS2.0 配信中

ASCII.jpメール デジタルMac/iPodマガジン