おもろそうな記事を見つけたので試してみた。
生でアセンブル言語を使用するのはちと敷居が高いので、インラインアセンブラから入ってみようという企画。ゆとりPGの自分にはちょうどいい。
用語の整理
- ロード メモリからレジスタに値を読み込むこと
- ストア レジスタの値をメモリに書き込むこと
- 汎用レジスタ いろんな計算に使える便利なやつ。EAX~EDXまであるようだ
とりあえず実践。出力は普通にcoutを使うよ。
#include <iostream>
using namespace std;
// iに100を代入して表示するだけのプログラム
int main()
{
int i;
__asm
{
mov i, 100;
}
cout << i << endl;
}
次にレジスタを使ってみる。
#include <iostream>
using namespace std;
// レジスタに0xFFFF0000をロードしてiにストアするプログラム
int main()
{
int i;
__asm
{
mov eax, 0xFFFF0000;
mov i, eax;
}
cout << hex << i << endl;// ffff0000
}
配列を扱うときは、インデクスの値に注意。インデクスを1つ増やしてもアセンブラでは1バイトしか移動しないようだ。そこで、Cでいうところの[sizeof(int)]と同じ役割を持つ[type 変数名]をインデクス値にかけてやる必要がある。
#include <iostream>
using namespace std;
//配列arrayに値を代入するプログラム
int main()
{
int array[4];
__asm
{
mov array[0], 100;
mov array[1*type array], 200;//1*sizeof(int)と同じ。これでポインタが4バイト移動する
mov array[2*type array], 300;
mov array[3*type array], 400;
}
for(int i=0;i<4; ++i)
{
cout << "array[" << i << "] = " << array[i] << endl;
}
return 0;
}
みんな大好きポインタ篇
#include <iostream>
using namespace std;
int main()
{
int i;
int *p = &i;//pにiのアドレスを格納
__asm
{
mov ebx, p;ポインタ用のレジスタEBXにpをロード
mov [ebx], 100;*pに100をストア
}
cout << i << endl;//100
return 0;
}
ポインタが指す実体を参照したい場合は、レジスタ名を[]で囲むといいようだ。ポインタ変数pに対する*pと同じことが、レジスタEBXに対する[EBX]で行えるというわけだ。
なお、__asmブロック内ではC/C++のコメント//や/**/が使えるほか、;の後ろも1行コメントとして認識されるらしい。
構造体も扱えちゃう
#include <iostream>
using namespace std;
//適当に構造体を作成
struct FOO
{
int val1, val2;
};
int main()
{
FOO a;//実体を作る
FOO *p = &a;//aへのポインタ
__asm
{
mov ebx, p//aのアドレスをレジスタEBXにロード
mov [ebx]a.val1, 100/*ポインタを参照してa.val1に100をストア*/
mov [ebx]a.val2, 200;同様にa.val2に200をストア
}
cout << "a.val1 = " << a.val1 << endl;// a.val1 = 100
cout << "a.val2 = " << a.val2 << endl;// a.val2 = 200
return 0;
}
次回は演算を勉強しよう…