Categories Books | Hard | Hardware | Linux | MCU | Misc | Publish | Radio | Repository | Thoughts | Time | UNIX | Writing | プロフィール
先日、インターフェース 2002年7月号の特集「Linux徹底詳解」の内容について、読者の方からメールを頂きました。内容は「Decompressing kernel... の部分でハングアップしてしまう」というもので、これまでにも同様のメールを他の方々からも頂いています。
発表後、2年近く立っているにもかかわらず、私の記事を辿りながら Linux 起動の仕組みを探求して頂いていることに感謝すると共に、全くフォローアップ出来ていないことを猛省・・。
ということで、「Linux徹底詳解」の世界を、このゴールデンウィークの間に再度探訪してみたいと思います。私自身もこの2年間で新しい知見を手に入れましたし、Linux もカーネル 2.6 で様変わりしています。ページ数の関係で、雑誌上では十分解説できていない部分もありましたので、この機会に補講しておくことにしましょう。「ツッコミ」も表示可能にしましたので、不明な点などありましたら、ドシドシ書き込んでやってください。
それでは、参りましょう!
2002年7月号は、発売後間もなく完売になってしまいました。お読みになりたい方は、図書館や、CD-ROM版インターフェースなどをご利用頂ければと思います。ちなみに、CQ出版はコピーサービスも行っていますが、本特集の場合、総額8000円を超えてしまうことになります・・。
プログラムの作成に入る前に、特集記事で触れることが出来なかった「サイズ・プレフィックス」について補講しておきます。
x86 がリアルモードとプロテクトモードという、2つの顔を持っていることはよく知られていますが、これとは別に x86 には「16 bit mode / 32 bit mode」というモードが存在します。
具体的にリアルモードで説明してみましょう。当然のことながら、リアルモード上は 16 ビットの世界です。オペランド値もレジスターも 16 ビット。セグメント機構を使っても、たかだか 20 ビットまでしかアクセスすることは出来ません。
・・というのが、巷の解説本に書かれている内容ですが、これは真実について半分しか言及していません。余り知られていませんが、「リアルモード上でも 32 ビットレジスタにはアクセスできる」のです。「うっそ〜〜〜!」という声が聞こえてきそうですが、ホンマです。ちなみに、逆もまた真なりで、プロテクトモード上で 16 ビットレジスターを操作することも可能です。
さて、ここからが面白いところです。「ふたつのビット長モードが存在するということは、16 ビット/32 ビットのそれぞれに対応する2種類の命令コードが存在する」ということになります。確認してみましょう。次のような、簡単な mov1.s を用意してください。
movl 0x12345678, %eax
これは、32 ビットの EAX レジスターに 32 ビット即値を転送するための命令です(32 ビット長のため、mov 命令に l (Long) suffix が後置されている点に注意)。それでは、アセンブルです。
$ as -o mov1.o mov1.s $ objdump -D mov1.o mov1.o: file format elf32-i386 Disassembly of section .text: 00000000 <.text>: 0: a1 78 56 34 12 mov 0x12345678,%eax Disassembly of section .data: $ wc -c mov1.o 449 mov1.o
全部で5バイトの機械語にアセンブルされました。即値の EAX レジスターへの転送命令は A1、その後ろに 0x12345678 が Little-endian 型式で格納されていることが分かります。
ところで、生成された mov1.o オブジェクトファイルのサイズを見てみると、449バイトあります。444バイトも水増しされていることになりますが、この原因は GCC プログラミング工房の読者の方々にはお馴染みの ELF (Executable and Linking Format)の冗長性にあります。「そんな無駄、ワシは許さ〜〜ん!」という方は、次の命令を実行あれ。
$ objcopy -O binary mov1.o mov1.bin $ wc -c mov1.bin 5 mov1.bin $ hexdump -C mov1.bin 00000000 a1 78 56 34 12 |.xV4.| 00000005
objcopy コマンドを使って、ELF オブジェクトファイル形式を単なるバイナリー型式に変換しています。-O (Output target) オプションがミソです。余分な情報はバッサリ切り捨てられ、丸坊主状態ですが、もう一度逆アセンブルして、その中身を確かめてみましょう。
$ objdump -D mov1.bin objdump: mov1.bin: File format not recognized
「ファイル形式が認識できない」という、エラーメッセージが表示されてしまいました。それもそのはず、mov1.bin には、実行コード以外には付帯情報が全く添付されていません。
このような場合のために、objdump には -b オプションが用意されています。これは BFD name の略であり、ファイル形式を指定するためのオプションです。mov1.bin はバイナリー型式ですから、binary を指定してください。
$ objdump -b binary -D mov1.bin mov1.bin: file format binary objdump: Can't disassemble for architecture UNKNOWN!
少し進みましたが、今度は「アーキテクチャが分からん」と言っています。全く世話の焼けるやつですが、アーキテクチャを指定するためのオプションとして -m (Machine)が用意されています。
$ objdump -b binary -m i386 -D mov1.bin mov1.bin: file format binary Disassembly of section .data: 00000000 <.data>: 0: a1 78 56 34 12 mov 0x12345678,%eax
お〜〜〜、5バイトの羅列が、見事逆アセンブルされました!こういう芸当は、統合開発環境では到底不可能です。さすがは、我らが GNU 開発ツール。
さて、ここで私からのちょっとした宿題です。次のコマンドを実行してみてください。
$ objdump -b binary -m i8086 -D mov1.bin mov1.bin: file format binary Disassembly of section .data: 00000000 <.data>: 0: a1 78 56 mov 0x5678,%ax 3: 34 12 xor $0x12,%al
i8086 というのは、名前から類推できる通り、x86 の 16 ビットアーキテクチャを意味しています。この逆アセンブルリストは、実に深い意味を孕んでいるのですが、私達の目の前で一体何が起こったのでしょうか?各自、一晩ゆっくり考えてみてください。