「プログラムは機械語で書かれている」を実感してみよう
よく「プログラムは機械語で書かれている」とか「意味ある二進数の羅列」だとか言われますが、 昨今の高級言語(C#やVBなど)ばかり使用しているとそれがいまいち実感しにくいものだと思います。 そこで、ここではちょっとだけ低いレヴェルでプログラムを見てみたいと思います。
MS-DOS用ヘッダとWindows用ヘッダがある
まずは何でもいいのでWindows(NT以降)で実行できるEXEファイルを用意します。 (勿論VS.NETで作ったEXEファイルでもよい)ここではWindowsに標準で付属している電卓に実験台になってもらいます。(^^;
このEXEファイルは全てPEフォーマットという形式で保存されています。 従って、どのEXEファイルも基本的な構造は統一してあるということです。 まず簡単にPEフォーマットを説明しておくと、ファイルの先頭部分にそのプログラムに関する情報を記録しておくヘッダ領域があります。 このヘッダ領域の前半部分はMS-DOS互換のヘッダで、後半がWindows用のヘッダとなります。 このような形式をとっている理由はWindows用実行ファイルが誤って、 MS-DOSで実行されてしまった際、MS-DOSからは通常のMS-DOS用実行ファイルに見えるようにし、 エラーメッセージを表示する為です。 (因みに.NET用実行ファイルはMSILを知らないWindowsでも実行できるように今のところは PEフォーマットになっており、実際のコード読み込みはmscoree.dllに任せています。)
スタブコードがエラーメッセージを表示する
ここで焦点を当てたいのは、”エラーメッセージを表示する”という部分です。 これを実現する為に、先のヘッダ部分にはスタブという小さなコードが埋め込まれているので、これをちょっとだけ覗いて見ます。
まずは、電卓の16進ダンプを見てみます。(バイナリエディタで表示できます。但し自己責任のもと実験してください。)
さて、一体何が書かれてるのかさっぱりですね。(笑)まず先頭の4D 5Aという2バイトの値ですが、 これはこのファイルが実行ファイルだという証です。その後、簡単なプログラム情報があって、 重要なのは5行目0Eというところからです。(青字で表示)ここからがさきほど書いたMS-DOSで誤ってWindows用EXEファイルを実行 してしまったときに実行されるコードです。ではこのままでは少々見難いのでアセンブリ言語に変換してみます。
これは上記16進数の青字部分です。左に16進数が、右にそれに対応するアセンブリ言語が表示されています。 さて、最後二行以外は画面にエラーメッセージを表示するための命令です。 上から順に説明していくと、まず、cs(コードセグメント)というレジスタの値をスタックにプッシュしています。 次に今プッシュされた値をds(データセグメント)に入れます。これは簡単にいうと、 コードの先頭アドレスをdsに入れたということです。次にdx(データレジスタ)に、表示したい文字列の先頭位置を オフセットアドレス(先頭からの相対値)として指定します。 これで、さきほどのdsレジスタとdxレジスタの値を用いれば、 メモリ上のどこに表示したい文字列が存在するのかがわかります。あとはシステムコールをするだけです。 これはOSの提供している機能を呼び出すことで、4,5行目でそれが行われています。 この命令によりOSは指定されたアドレスから$文字が出現するまでの文字列を画面に表示してくれるというわけです。 では実際に表示される文字列がどこにあるかとういと、上記16進数コードの緑字になっている部分です。 人間が読める文字に直すと次のようになります。
つまり、上記の文字列が表示されるということです。そして、アセンブリ言語の最後二行は終了のためのコードで、 使用していたメモリーの開放などを行います。
どうでしょうか、このようにしてみると、計算機(PCなど)が2進数で動いているというのも実感できるというものです。