Vmlinux

Linuxシステムにおいて、vmlinuxとは、内部にLinuxカーネル本体を包含する静的リンクされた実行ファイルである。ELF、COFF 、a.outのような実行可能バイナリ形式に準じた形式が利用されるが、通常の実行可能バイナリと異なりカーネルが対応している形式ではなく、ブートローダーが対応している形式でなければならない。//vmlinux//ファイルはカーネルデバッグ、カーネルのシンボルテーブル生成、またはその他の用途で利用される。通常、コンパイラが生成するバイナリから、さらに全てのシンボルを取り除き、圧縮をかけ、Multiboot Specification用ヘッダ、ブートセクタ、BIOS用ローレベルブートセットアップルーチン、自己伸長ルーチンなどを追加して最終的に、ブート可能なイメージが完成する。通常はカーネルのビルドが正常終了すると、ソースコードのトップディレクトリにこのファイルが存在する。

1. 語源
-----

古くから、UNIXのカーネルイメージはunixというファイル名であり、cp  /unixのようにコピーしてインストールされていた。BSDで仮想記憶が実装され、仮想記憶をサポートしたカーネルであることを示すvm-という接頭辞を付けvmunixという名前が使われるようになった。//vmlinux//という名前はそのvmunixを基にした命名法によるものである。さらにLinuxでは圧縮イメージという機能も追加され、//vmlinuz//という名前が付けられた。vmlinuxを圧縮したものであることを表す文字zを後尾に付している。

2. ロード
------

Unix系システムにおける古くからの慣習で、カーネルはルートディレクトリ  に置かれることが多かった。しかし、Linuxに限らずPC-UNIXでは、ブートローダがハードディスクアクセスにBIOSを使用するため、ハードディスクの先頭1024シリンダー  までしかアクセスできないという制限があるシステムがあった。

この制限に対処するため、Linuxディストリビューターは、ユーザにハードディスクの先頭にブートのためのファイルシステム、すなわちカーネルと、システムのブートに必要なファイルを置くパーティションを作成するよう推奨した。

慣習として、ブート後にそれとは別のパーティションにあるファイルシステムをルートとする場合は、このブート専用ファイルシステムはブート後は /boot にマウントされた。のちにこれはFilesystem Hierarchy Standard  により標準化された。詳しくは、[1]を参照してほしい。

3. 圧縮
-----

旧来より、ブート可能なカーネルイメージを生成した際、カーネルはまた、zlibアルゴリズムを用い圧縮されている。Linuxカーネルバージョン2.6.30からはこれに加え、圧縮率が高いLZMAやBZIP2アルゴリズムによる圧縮もサポートされている。システムに電源を投入し、BIOSがブートローダを読み込み、ブートローダが圧縮されたカーネルイメージコードを読み込む。このコードからカーネルコードが伸長されると、いくつかのシステムでは、ブートプロセスが進行するにつれコンソールにドットが何個も表示される。

圧縮ルーチンは、いくつかのアーキテクチャ、とりわけ、i386のようにブート時に読み込めるデータサイズが極端に制限される場合必須であったが、//bzImage//が開発された現在においては、ブートプロセスにおいては、取るに足らない要素である。

x86アーキテクチャとは異なり、SPARCアーキテクチャにおいては、カーネルイメージはvmlinuxファイル自体を単にgzipで圧縮したものである。これはSPARC Linuxシステムにおいて使用される、SILO ブートローダがgzipで圧縮されたイメージを透過的に伸長できるからである。

ブートイメージのファイル名はさほど重要ではなく、しかし、慣習的には、vmlinuz または zImageとなる場合が多い。

4. bzImage
----------

Linuxカーネル開発が成熟するにつれて、ユーザーが生成するカーネルのサイズはいくつかのアーキテクチャにおいて課される制限である、圧縮されたカーネルコードが保持可能なサイズを越えるまでになってきた。

この制限に対処するため、カーネルを不連続なメモリ領域にうまく分離した、bzImage  フォーマットが開発された。

bzImageはzlibアルゴリズムを用い圧縮されている。また2.6.30からは更によりよいアルゴリズムで圧縮可能である。もっともらしい誤解は、//bz//がファイル名の接頭辞にあるため、このイメージがbzip2で圧縮されているのだということが語られるが、そうとは限らない。

4.1. カーネルイメージのビルドとフォーマット
------------------------

Linuxカーネルイメージは通常、Linuxカーネルソースのディレクトリにおいて次のコマンドを実行することで得られる。

現行のバージョン2.6では、アーキテクチャによって、このとき暗黙のうちに指定されるターゲットは異なる。例えばx86アーキテクチャにおいては、暗黙のうちに

と指定されている。これはbzImageを生成せよとの指令を発行したことになる。 正常にビルドが進むと、端末エミュレータに以下のように表示される。

[... ビルドプロセス ...]カーネルに静的リンクされる全てのオブジェクトコードはvmlinux.oにリンクされる。これとは別に、全てのオブジェクトファイルからシンボルのみを取り出し、単一のELFセクションヘッダとして保持するオブジェクトコード.tmp_kallsyms2.oが生成される。この2つのファイルをリンクしたものが本記事の対象とする実行ファイルvmlinuxである。続いてこのファイルにnmコマンドをかけ、シンボルテーブルSystem.mapファイルを生成する。続いて圧縮ルーチンを含めたカーネルイメージのブート用ルーチンのビルドが開始される。

カーネルの圧縮、カーネルイメージの伸長などに関するソースコードはarch/x86/boot/compressedに存在する。

arch/x86/boot/compressed/head_$.oはカーネルイメージのメモリアドレス前方に位置し、BIOSから得た低レベルなハードウェアの情報を処理するためのコードである。詳細はソースコードのarch/x86/boot/compressed/head_$.Sやそのエントリポイントstartup_$、リンカスクリプトなどを参照せよ。

arch/x86/boot/compressed/misc.oは後方に位置するカーネル本体を含むコードをzlibなどのアルゴリズムを用いて伸長するコードである。有名な//Uncompressing Linux...//というコンソールの表示はこの処理において見られる。

head_$.o, misc.oその他カーネルイメージの伸長後に利用する低レベルコードをビルドし終わると、piggy.oというオブジェクトコードと一緒にリンクされ、arch/x86/boot/compressed/vmlinuxという実行ファイルを生成する。piggy.oは次のようなプロセスをたどり生成される。ディレクトリのトップにあるvmlinuxは、GNU Binutilsにより配布されるobjcopyコマンドを利用し、.commentなど不要なELFセクションヘッダとシンボル情報を全て削除されたうえで実行ファイルarch/x86/boot/compressed/vmlinux.binに変換される。このファイルに圧縮をかけ更に専用のツールを用いて、vmlinux.bin.gzをELFのセクションヘッダに埋め込んだ特殊なELFオブジェクトファイルが生成される。これがpiggy.oである。

この後ブート用の低レベルコードのビルドが続く。カーネルのブートに関するコードは前述の圧縮・伸長コードも含め、arch/x86/bootに存在する。

arch/x86/boot/header.oはカーネルイメージの先頭メモリアドレスに存在するコードである。エントリーポイント_startから開始されるこのコードにより前述した伸長用ルーチンを後ほど呼び出す。

このコードは以前のリリースにおける、2つのコードbootsect.o、setup.oの一部を抜きだし、再構成したものである。ちなみにbootsect.oはフロッピーディスク用のダイレクトブート用コードであったがバージョン2.6では、header.Sの一部にダイレクトブートできない旨のメッセージを表示するコードのみ残っているに過ぎない。setup.oの残部は細かく分けられ、一部は前述のhead_$.oにも含まれている。このオブジェクトファイルも含め、ビデオBIOS用処理などの低レベルなコードがarch/x86/boot/setup.elfという実行ファイルとしてリンクされる。

ここまで正常に終了したならば、bzImageの完成は目前となる。arch/x86/boot/setup.elfとarch/x86/boot/compressed/vmlinuxはobjcopyコマンドの特殊なオプションによりそれぞれELFバイナリからrawバイナリarch/x86/boot/setup.binとarch/x86/boot/vmlinux.binに変換される。この二つをカーネルビルド時にしか使われない専用ツールで結合すると、arch/x86/boot/bzImageが完成する。

ビルドの終了メッセージの意味は次の通りである。 "Root device is "、これはルートディレクトリのマウントされているファイルシステムはメジャー番号8番、マイナー番号3番にあることを予めカーネルイメージに埋め込んだことを示す。すなわちこれはSCSIディスクの第一番目のディスク先頭第3パーティションにルートファイルシステムがあることを示す。次の2行はカーネルイメージのデータサイズを示している。CPUがリアルモード状態のときに使用されるセットアップコードは、セクタサイズにきれいに収めるため、512の倍数となる15360バイトにパディングされたことを通知している。"System"はカーネル本体を含むコードでこの場合1MBをゆうに越え、2828kBとなっている。続いてイメージのCRCが検出され、これが初回のビルドであることを通知し、ビルドプロセスは終了する。

以上よりbzImageファイルは特殊なバイナリフォーマットを持っている: すなわち、主に次のデータを連結し、構成されていることが分かる。

4.2. ブートプロセス
------------

bzImageが開発された経緯の通り、アーキテクチャによってはブート開始直後のメモリ領域は非常に限られている。bzImageは限られたメモリ領域を有効活用するため、ジャンプ命令などを巧みに利用しており、その処理は一般には複雑である。x86システムのブートでは、BIOSから起動されたブートローダがカーネルイメージをメモリにロードする。このとき、カーネルイメージは前項の2セクションで分割した上でロードされる。"Setup"部分がブードローダの直後のメモリアドレスにBIOSなどの予約エリアを上書きしないようにロードされる。"System"はメモリアドレス0x100000から後方にロードされる。initrdは"System"より後方のメモリアドレスにロードされる。"Setup"はBIOS割り込みルーチンを駆使し、header.oなどの処理を経てhead_$.oコードに移行し、CPUをプロテクトモードに遷移する。続いて、head_$.oからmisc.oが呼び出されその後続のデータとなっているカーネル本体が伸長される。伸長後はより複雑な処理となる。以降の処理内容は順に述べるのみとし、必要ならばソースコードを参照して欲しい。伸長済みのカーネル本体に処理を移すと、

ハードウェアの低レベル初期化
仮想記憶の有効化などを含むメモリ管理の開始
CPU認識と特定の処理実行、SMP関連の処理実行ここまではアセンブラコードが多く含まれている。以降はアーキテクチャ非依存となる。

init/main.oのstart_kernelに処理が移り

カーネルパラメータの解析
割り込み
メモリ管理システムの残部の起動
カーネルスレッドの起動、マルチタスク処理とスケジューラ起動
デバイスドライバの初期化
initrdのマウントとファイルシステムの初期化
"真の"ルートディレクトリのマウント
init起動準備 を行い、システムのブートアップが完了する。

4.3. カーネルイメージの伸長
----------------

現時点ではbzImageファイルを伸長する特定のツールはない。しかし、カーネルソースコードのアーカイブ内に[2]というbashベースの簡易なシェルスクリプトが存在する。このスクリプトは、引数に与えたイメージを伸長し、イメージからカーネルビルドコンフィグレーションを抽出する。場合によっては、伸長したイメージを直接得るため、bzImageを改変することも可能である。いくつかのディストリビューション、例として、RedHatとそのクローンにはカーネルのRPMパッケージに対応するvmlinuxファイルを持つkernel-debuginfoなるパッケージがあるかもしれない。概して、そのようなパッケージは/usr/lib/debug/lib/modules/`uname -r`/vmlinuxにインストールされる。

5. オブジェクトファイルフォーマット
-------------------

以下は、x86-64アーキテクチャにおけるGentoo Linuxで稼働する、カーネルの実行可能イメージからヘッダ情報を抽出したものである。

ちなみに、同じコマンドをbzImageに実行しても次のようなエラーが返されるだけである。

bzImageは前述の通りELFヘッダを持たないrawバイナリである。

6. 脚注
-----

6.1. 注釈
-------

6.2. 出典
-------

7. 関連項目
-------

Linuxカーネル
ローダブル・カーネル・モジュール
オブジェクトファイル
System.map
LILO
GNU GRUB
initrd
init
メモリ管理
仮想記憶
ページング方式

8. 外部リンク
--------

[3]
[4]
[5] Linux JFプロジェクト
[6] ポポロイア記念文化センター
[7]
[8]
[9] IBM dW
[10]