9.12 アセンブリ言語
C 言語にアセンブリ言語を埋め込む
C 言語は人間が理解しやすい高水準言語に分類されますが、高水準言語の中では極めて機械語に近い存在でもあります。そのため、低水準言語と呼ばれる機械語に近いプログラミング言語であるアセンブリ言語との相性も良いと考えられます。アセンブリ言語は高水準言語とは異なり、機械語に直接翻訳することが可能な言語で、ひとつのステートメントがひとつの機械語に対応しています。
現代では、ほとんどのプログラマがアセンブリ言語を使わなくなりましたし、アセンブリ言語を知らなくてもプログラマになることができます。では、本当にアセンブリ言語は必要のない言語なのでしょうか。ところが、実践の開発を行うと意外とアセンブリ言語の知識が必要になる場面に遭遇します。例えば、高度なゲームプログラマになるためにはアセンブリ言語は欠かせません。CPU の特定の命令セット(※1)をアセンブリ言語から明示的に用いることによって、演算速度を高速化させることができる技術などが存在するためです。
または、オペレーティングシステムの研究を行う場合も、アセンブリ言語の知識は必要になります。現代の多くのオペレーティングシステムは C 言語で記述されていますが、その基本部分にはやはりアセンブリ言語を使わなくてはなりません。
このように C 言語とアセンブリ言語の関係は極めて密接なものがあります。多くのプログラムは C 言語を用いて実現することができますが、プログラムの一部でハードウェアの機能を直接操作するような必要がある場合、アセンブリ言語を使わなくてはなりません。このような事態に備え、一部のコンパイラでは C 言語のソース内にアセンブリ言語を記述することが可能になっています。これをインライン アセンブラと呼びます。
インライン アセンブラは、純粋なアセンブリ言語ではなく、通常は C 言語とある程度協調することができます。例えば、アセンブリから C 言語の変数や関数を呼び出すというようなことができるかもしれません。C 言語のインライン アセンブラは標準ではなく、開発環境に依存するものなので、コンパイラによってはまったくアセンブラをサポートしていない場合があります。もちろん、アセンブリ言語は CPU の命令セットに依存するため、使われるアセンブリ言語もコンパイルする環境によって異なります。C 言語とは異なり、アセンブリ言語には標準という考え方がないのです。そのため、開発環境がインライン アセンブラをサポートしているか、どのような命令が使えるかという問題は、本書の範囲を超えています。使っている開発環境のヘルプ等を参照してください。
一般的には、インライン アセンブラには asm というキーワードが用いられます。本書執筆時点でもっとも有名なコンパイラのひとつである Microsoft Visual C++ では、__asm キーワードを用いてインライン アセンブラを記述することができます。
__asm アセンブラ命令
__asm { アセンブラ命令リスト }
__asm キーワードの後にアセンブリ言語の命令を記述することができます。複数行の命令を記述したい場合は { } を用いて __asm ブロックを作成します。1行アセンブラであれば __asm キーワードの直後にステートメントを記述します。
#include <stdio.h> char strInputMessage[] = "2 つの整数を入力してください>"; char strScanf[] = "%d %d"; char strResult[] = "%d + %d = %d\n"; int main() { int x, y; __asm { push offset strInputMessage call dword ptr printf add esp, 4 lea eax, [y] push eax lea ecx, [x] push ecx push offset strScanf call dword ptr scanf add esp, 0Ch mov eax, x mov ebx, y add eax, ebx push eax push y push x push offset strResult call dword ptr printf add esp,10h } return 0; }
コード1は、__asm キーワードを使ってインライン アセンブラで記述した C 言語プログラムの例です。このプログラムは Microsoft Visual C++ 6.0 でコンパイルされることを想定しています。Microsoft Visual C++ のインライン アセンブラでは Intel 486 プロセッサの命令セットをサポートしています。
アセンブリ言語の解説は特定のコンピュータに依存する上、本書の範囲内ではないので省略しますが、コード1のインラインアセンブラは C 言語の printf() 関数と scanf() 関数を呼び出しています。アセンブラの中に C 言語の変数名や関数名が使われていることに注目してください。プログラムは 2 つの整数を x 変数と y 変数に入力し、これらを加算した結果を表示して終了します。
このように、C コンパイラの中にはインラインアセンブラをサポートしているものがあるので、演算速度が問われるプログラムなどではアセンブリ言語を使うことができます。