ローカル変数です。スタックというのは便利です。これに入れることによって演算命令等はレジスタを意識すること無いプログラムが出来ます。ですが、いくつもの変数を作りたくさんの関数を呼ぶようなときにスタックだけでは力不足です。そこで今回の主役ローカル変数の登場です。
.assembly extern mscorlib{} .assembly localver{} .method public static void main() cil managed { .entrypoint .maxstack 1 .locals (int32 a) //変数を宣言 ldc.i4.0 //スタックへ0を積む stloc.0 //スタックから、ローカル変数の0番へ値を移動 ldloc.0 //ローカル変数の0番から、スタックへ値をプッシュ call void [mscorlib]System.Console:: WriteLine(int32) ldloc.0 //再びローカル変数の0番からスタックへ値をプッシュ call void [mscorlib]System.Console:: WriteLine(int32) ret }
内容としては0を二回出力しているだけです。別に変数を使う必要性はないですが、あえて使っています。
ローカル変数内部でunsigned int16のラベルが付けられます。そのため「0番から65534番」までの65535個が使えます。変数は宣言した順番に0番柄の番号が割り振られ、その番号を使ってスタックと値をやりとりします。ですが、この方法はある意味すごく分かりづらいです。そのため、宣言時に付けた名前を利用して書くことも出来ます。
したのはラベルを使った場合。
.assembly extern mscorlib{} .assembly localver{} .method public static void main() cil managed { .entrypoint .maxstack 1 .locals (int32 a) //変数を宣言 ldc.i4.0 //スタックへ0を積む stloc a //スタックから、ローカル変数「a」へ値を移動 ldloc a //ローカル変数「a」から、スタックへ値をプッシュ call void [mscorlib]System.Console:: WriteLine(int32) ldloc a //再びローカル変数「a」からスタックへ値をプッシュ call void [mscorlib]System.Console:: WriteLine(int32) ret }
これら2つは同じ事が出来ます。
同じ名前の変数をいくつも宣言することが来ます。その場合に変数名を利用すると、その変数名のうちで一番最初に宣言されたもをアセンブラが選びます。それぞれ実験してみてください。
上と反対に型名だけ宣言して、名前をつかないことも可能です。この場合は、変数についている数を指定することで利用することが出来ます。
下のサンプルはちょっと長いですが、これらのことをふまえたローカル変数へのアクセスの例です。
.assembly extern mscorlib{} .assembly localver{} .method public static void main() cil managed { .entrypoint .maxstack 1 .locals (int32 a,int32 a,int32 b) .locals (int32,int32,int32 c)//分割して書くことも出来る。 //0番目「a」にアクセスするとき ldloc.0 //一番短いコードになる stloc.0 //一番短いコードになる ldloc.s 0 //2行下と同じコード stloc.s 0 //2行下と同じコード ldloc.s a stloc.s a ldloc 0 //2行下と同じコード stloc 0 //2行下と同じコード ldloc a stloc a //1番目「a」にアクセスするとき ldloc.1 //一番短いコードになる stloc.1 //一番短いコードになる ldloc.s 1 stloc.s 1 //ldloc.s 1 この方法ではアクセスできない //stloc.s 1 ldloc 1 stloc 1 //ldloc a この方法でアクセスできない //stloc a //2番目「b」にアクセスするとき ldloc.2 //一番短いコードになる stloc.2 //一番短いコードになる ldloc.s 2 //2行下と同じコード stloc.s 2 //2行下と同じコード ldloc.s b stloc.s b ldloc 2 //2行下と同じコード stloc 2 //2行下と同じコード ldloc b stloc b //3番目「」にアクセスするとき ldloc.3 //一番短いコードになる stloc.3 //一番短いコードになる ldloc.s 3 stloc.s 3 ldloc 3 stloc 3 //4番目「」にアクセスするとき ldloc.s 4 stloc.s 4 ldloc 4 stloc 4 //5番目「c」にアクセスするとき ldloc.s 5 //2行下と同じコード stloc.s 5 //2行下と同じコード ldloc.s c stloc.s c ldloc 5 //2行下と同じコード stloc 5 //2行下と同じコード ldloc c stloc c ret }
コンパイル後のコードは小さい方が良いと思います。上のサンプルでは上に行くほど小さいコードがはき出されます。ちょっとまとめると
これらでアクセスできる「0~3」までのローカル変数は1バイトのコードで操作を行えます。よく操作する値はこれらで扱うと良いかもしれません。
これは、後ろに変数名又は変数番号を取ります。指定できるのは「0~255」までです。2バイトのコードになります。
全ての変数へアクセスできます。4バイトのコードになります。
これでとりあえず順次実行なプログラムは組めるでしょう。次回は分岐を行ってみたいと思います。