はじめに
本稿では、Microsoft Visual C++のインラインアセンブラを用いて、アセンブリ言語の基本的な命令セットを学習します。本来のアセンブリ言語は、単純にアセンブリ言語の文法を覚えるだけでは使うことができず、CPUが内部で何を行っているのかや、メモリアドレスに関連した高度な知識が必要になります。しかし、インラインアセンブラであれば、多くのプログラマが使い慣れているC言語の内部にアセンブリ言語を埋め込むことができるので、スムーズにアセンブリ言語の学習ができます。インラインアセンブラであればメモリアドレスの計算などが不要で、C言語で宣言された変数などの識別子をそのまま利用することができるのです。アセンブリ言語初心者が、アセンブリ言語の学習を開始するのに非常に適しているでしょう。
インラインアセンブラの基本については、前稿『インラインアセンブラによるアセンブリプログラミング体験』を参照してください。
算術命令
C言語のような高水準言語では加算や減算などの算術操作は10+5というように、数学の記法に近い式として記述することができました。しかし、アセンブリ言語では、式を表記することはできず、基本的な計算も含めて、あらゆる処理が命令によって記述されます。なぜならば、アセンブリ言語はコンピュータが直接理解することができる機械語と1対1の関係を持っているためです。アセンブリ言語の命令は、オペコードと呼ばれる機械語の命令値に対応しています。
最も基本的な計算である加算はADD命令を使います。ADD命令は次のように記述します。
add dest , src
ADD命令は、ソース・オペランドに指定された値とディスティネーション・オペランドに指定されたレジスタまたはメモリの値を加算し、その結果をディスティネーション・オペランドにストアします。こうした性質から、ソース・オペランドには即値を含め、メモリとレジスタを指定することができますが、ディスティネーション・オペランドには即値を指定することはできません。
#include <stdio.h> int main() { int result; __asm { mov eax, 10; add eax, 100; mov result, eax; add result, 40; } printf("result=%d\n", result); return 0; }
result=150
sample01の__asmブロックでは、最初に加算演算で利用するEAXレジスタの値を初期化する目的で10を設定し、10を保存するEAXレジスタを対象にADD命令で100を加算しています。このADD命令を実行すると、CPUは即値100とEAXの現在の値を加算し、その結果をディスティネーション・オペランドであるEAXに保存します。よって、EAXの値はADDを実行した時点で上書きされるので注意してください。
その後、EAXレジスタの値をresult変数にストアし、さらにresult変数の値に40加えます。ADD命令のディスティネーション・オペランドにはメモリを指定することもできるので、問題はありません。
sample01の実行結果では、最終的なresult変数の値を表示させています。resultの値は、上記の通り150となります。
減算の場合も、基本的な操作は加算命令と同じです。減算を行う場合はSUB命令を使います。
sub dest , src
SUB命令の考え方はADD命令と同じです。この命令では、ディスティネーション・オペランドの値からソース・オペランドの値を引き、その結果をディスティネーション・オペランドにストアします。ソース・オペランドに即値を指定することはできますが、ディスティネーション・オペランドには指定できません。
#include <stdio.h> int main() { int result; __asm { mov eax, 100; sub eax, 30; mov result, eax; sub result, 20; } printf("result=%d\n", result); return 0; }
result=50
sample02は、最初にEAXレジスタに100をロードし、この値からSUB命令を用いて30を引きます。この時点でEAXレジスタの値は70になっています。次に、EAXレジスタの値をresult変数にストアし、さらにSUB命令でresult変数の値から20を引いています。よって、このプログラムの結果resultの値は50となります。
