スタックとレジスタ

関数呼び出しにおいて,実引数はスタックまたはレジスタで渡されます。

適当なコンパイラでは関数は「まずスタックを読み込み,読み切ったら今度はレジスタから読み込む」という方式を採用しているようです(Borland,EasyIDECなど)。

これを利用して,次のようなコードが書けます。

#include <stdio.h>

int main(void){
	int i = 3, j = 11, k = 36;
	printf("%d %d %d\n");
	printf("%d %d %d %d\n", j * k = i * j = 5);
}

これをEasyIDECで実行すると,

「36 11 3

75 15 5 3」

と出力されます。printf関数は,「%d」を見つけて次の引数を読み込もうとしますが,スタックに何も格納されていないので,レジスタから値を読み込んでいるのです。

というかそもそもこのコード,左辺値でないものに代入しています。これは本来コンパイルエラーになるはずですが,EasyIDECはアマアマですね,プロじゃない。

どうやらEasyIDECは右から計算するようです。「j = 5」「k = i * j」「j * k」の順に計算され,EAXレジスタには75,ECXレジスタには15が残されます。printf関数はこれを読み込んでいるわけです。

恐ろしいですね。

 

やっぱりgccやclangを使いましょう。