アセンブリ言語とは何か: アセンブリ言語入門 1

アセンブリ言語とは、CPU の処理する機械語を人間の理解できる記号に置き換えた言語です。とアセンブリ言語は機械語と(ほとんど)一対一に対応することが特徴です。たとえば、

add $t0, $s1, $s2

はアセンブリ言語で書かれたプログラムの一例であり、これは以下の機械語に対応します。

00000010001100100100000000100000

この機械語のうち最初の 6 桁 000000 と最後の 6 桁 100000 が add 命令であることを示し、次の 5 桁 100001 が第二引数が $s1 という変数(正確には後の章で紹介するようにレジスタ)であることを示し、次の 5 桁 10010 が第三引数が $s2 であることを示し、次の 5 桁 01000 が第一引数が $t1 であることを示しています。

このように、機械語の各部分を見れば機械的に機械語からアセンブリ言語に、あるいはアセンブリ言語から機械語に変換することができます。アセンブリ言語から機械語へ変換することをアセンブルといい、アセンブリ言語から機械語へ変換するプログラムのことをアセンブラといいます。

アセンブリ言語から機械語への変換は機械的に行えるため非常に簡単であることが重要です。少し訓練すれば、仕様書やコード表を見ながら手動でアセンブリ言語から機械語に変換することもできるようになります。手動でアセンブリ言語から機械語に変換することをハンドアセンブルと言ったりします。

アセンブリ言語のプログラムと機械語のプログラムは示す内容は同一でも見た目は全く異なります。01 の羅列である機械語は素人が見ても何のことか分かりませんが、アセンブリ言語であれば足し算を行っていることくらいは素人でも判断ができます。この見た目の違いが人間にとっては重要です。

C や Python などの高級言語な無かった昔は、まずアセンブリ言語でプログラムを書いて、これをハンドアセンブルして機械語に翻訳し、CPU に入力していました。

しばらくすると、アセンブラが登場し、ハンドアセンブルの手間が省けるようになりました。複雑な動作をする高級言語の処理系の実装は人的リソースと計算リソースの関係で昔は実現できませんでしたが、機械的な置き換え作業を行うアセンブラであれば実装できたのです。

その後、高級言語の処理系が発展し、アセンブリ言語に接する機械は少なくなりましたが、可読性と効率性のため、現代においても多くの場合高級言語はまずアセンブリ言語に翻訳され、そこからアセンブラが機械語に直すという二段階のステップを踏み、アセンブリ言語は未だに中間言語としての役割を果たしています。

アセンブリ言語とはあくまで総称であり、さまざまなアセンブリ言語が存在することに注意してください

まず、CPU とプログラムのインターフェース(ざっくり言えば機械語の仕様)をまとめたものを命令セットアーキテクチャといいます。たとえばインテルの x86 CPU と ARM v8 CPU が受け付ける機械語とその仕様は異なり、これらは別の命令セットアーキテクチャを持つといえます。

機械語とアセンブリ言語は一対一に対応するので、命令セットアーキテクチャが異なれば別のアセンブリ言語を使うことになります。つまり機械語の数だけアセンブリ言語があるということです。

冒頭で示したアセンブリ言語と機械語は MIPS というアーキテクチャのものです。たとえば x86 CPU では同じ加算命令でも引数の数や変数(レジスタ)の名前が異なり、

add EAX, EBX

のように書かれます。また、同じ x86 用のアセンブリ言語の中でも、AT&T 記法とインテル記法という二つの方言のような細かな記法の違いをもつ変種のアセンブリ言語が存在します。

最後に、冒頭で(ほとんど)一対一に対応するといった「ほとんど」の意味について解説しておきます。

機械語がサポートする命令の種類は、ハードウェアを単純にするため、非常に限られています。たとえば、変数の代入命令すら対応する機械語命令がない場合があります。

しかし、プログラマとしてはたくさんの種類の命令を使いたいという要求があります。

そこで、アセンブリ言語に擬似的な命令を加えてサポートするといったことが行われます。プログラマ風に言えば、糖衣構文が用意されているということです。たとえば、

mov $t0, $s1

とアセンブリ言語内で書くと、

add $t0, $s1, $zero

つまり変数 $s1 とゼロを足して $t0 に代入するという命令にアセンブラは自動で置き換えて翻訳します。

これにより、機械語が代入命令をサポートしていなくても、加算命令さえサポートしていればアセンブリ言語で代入命令が使えるようになるということです。もちろん、プログラマの側が代入操作を行うたびに add 命令を使って書いても良いのですが、こうすると可読性が下がってしまいます。アセンブリ言語プログラム内で mov 命令が使えるようになることで、読みやすいアセンブリ言語プログラムが実現できます。

ただし、この擬似命令を導入すると、翻訳結果の機械語を見ても、元のアセンブリ言語が mov であったか add であったかが分かりません。このことから厳密に機械語とアセンブリ言語が一対一に対応している訳ではないと言えます。

とはいえ、一対一でなくなる例といってもこの程度の置き換え操作で済む話しのみであり、アセンブリ言語から機械語への翻訳が簡単であることは変わりません。これ以上に複雑な処理が必要な場合には高級言語の処理系により実現されます

まとめ

  • アセンブリ言語は 01 列からなる機械語を人間の理解できる記号に置き換えた言語
  • アセンブリ言語と機械語はほとんど一対一に対応するので置き換えが簡単
  • 機械語の数だけアセンブリ言語がある