第10回
制御構造と変数(6)~if、for、whileをアセンブリ言語で

繰り返し処理をアセンブリ言語で

今度は、forとwhileによる繰り返しの構造をアセンブリ言語で記述してみましょう。

forとカウンタ変数

カウンタ変数にiを用い、処理を10回繰り返すCのソースはリスト3のようになります。

アセンブリ言語ではカウンタにCXレジスタを用い、CMP命令でその値を調べた結果によりラベルにジャンプします。このとき処理をもう一度繰り返すなら、ジャンプ先のラベルはCMP命令より後方(上方向、行番号の若い方向 ※1 )になります。

リスト4がアセンブリ言語で記述したforループ《的な処理》です。図2も参照してください。処理を実行するたびにCXレジスタの値を加算していき、forでいう継続条件を満たしていれば上のラベルに戻って処理を繰り返します。

ソースファイルは上から下へと処理が進むことを前提としているため、行番号の若い方(上方向)を後方、行番号の大きい方(下方向)を前方と呼びます。一般の文書だと前方とか先頭という言葉は上方向を示しますが、プログラムのソースは上から下=行番号小→大――と進むため、進行方向を先頭、前方と表現するのです。語の検索でも「前方検索」と言えばファイルの始めから終わりに向かって語を探していきます。これと同じ考え方です。
リスト3:処理を10回繰り返すforを使ったCのソース
	for (i = 0; i < 10; i++) {
	    : <処理>
	}

リスト4:Cのforループと同じ働きをするアセンブリ言語のソース
	MOX CX, 0 --------“XOR CX, CX”とした方が速い ※2 
	FOR_START:
	  : <処理>
	INC CX ----------- CXの値を1増加
	CMP CX, 10
	JL FOR_START ----- CXの値が10より大きければ上に戻って繰り返す
	  :

レジスタの保持する値を0にする場合、MOV命令で0を転送するよりXORを使って同じ値の排他的論理和を採る方が処理が速くなります。XOR命令では、各ビットが同じ値(0と0または1と1)なら結果は必ず0になります

便利なLOOP命令

アセンブリ言語にはLOOPという便利な命令があります。文字通りループ構造を作るための命令で、CXレジスタに保存された値を1ずつ減算していき、0でなければラベルに移動するという仕様です。

これを使うと、リスト4より簡単にforと同じ形の繰り返し構造を作れます。リスト5を参照してください。

forによる繰り返しと同じ処理は、実はforを使わなくてもCで記述できます。Cには、アセンブリ言語のJMP命令と同じように無条件ジャンプを行う命令gotoがあります。使い方はJMPと同じで、
goto <ラベル>;
と記述するだけです。これを使えば、forと同じ処理をリスト6のように記述できます。

リスト5:LOOP命令を使った繰り返し処理
	MOX CX, 10 -------- CXに繰り返し回数をセット
	FOR_START:
	  : <処理>
	LOOP FOR_START ---- CXが0でなければ上に戻る
	  :

リスト6:forを使わないで記述したCの繰り返し処理
	i=0;               /* 初期設定式 */
	FOR_LABEL:
	  : <処理>
	i++;               /* iを増分(再設定式) */
	if (i > 10) {      /* 継続条件 */
	  goto FOR_LABEL;  /* iが10より大きければ上に戻る */
	:

whileをアセンブリ言語で

次はwhileです。繰り返し回数を指定しなくてもよいwhileは、アセンブリ言語ではとても簡単に記述できます。リスト7のようなCのソースは、アセンブリ言語だとリスト8のようになります。図3も参照してください。

同じ処理構造をCでgotoを使って記述すれば、リスト9のようになります。個々の処理についての説明は不要でしょう。繰り返し処理では、継続条件を満たしていれば必ず処理は上(後方)に、満たしていなければ下(前方)に移動します。

リスト7:変数cの値がNULL(0)でない間処理を繰り返すwhileを使ったCのソース
	while (c != NULL) {
	    <処理>
	}

リスト8:Cのwhileループと同じ働きをするアセンブリ言語のソース
	WHILE_START:
	CMP AX, 0 ---------- AXの値が0か調べる(継続条件)
	JE WHILE_END ------- 0ならループを抜ける
	  <処理>
	JMP WHILE_START ---- 上に戻って繰り返す
	WHILE_END:
	  :

リスト9:whileを使わないで記述したCの繰り返し処理
	WHILE_LABEL:
	if (c != NULL) {      /* cがNULL(0)でなければ処理を実行  */
	    : <処理>
	  goto WHILE_LABEL;   /* 無条件で上に戻る */
	}
	  :


上に戻るか下に進むか?

ifによる条件判定では、移動先のラベルが下(前方)となりますが、forやwhileによる繰り返し処理(ループ)では
継続条件が真なら上(後方)
偽なら下(前方)
となります。

Cでifやfor、whileを使わない書き方を見れば、ifにはif以外の書き方がありませんが、繰り返し処理のforとwhileではifとgotoを使って別の書き方ができることも分かりました。

要するにこのことは『繰り返し処理は条件判定と分岐の変形である』ということを示しています。

あとがき

hiropの『ちょっと気になる専門用語』~《スパゲティ》

forやwhileを使わないで繰り返し処理を実現するため、無条件に処理先を切り替えるCのgoto命令を使いました。ご存じとは思いますが、何重にもネストした深いループから一気に抜け出すような場合を除き、gotoは極力使わないのが基本です。

gotoを使うとソース中のあちこちに自在に移動できてしまい、整然とした処理構造を維持できなくなるためです。gotoを使って処理の移動先がバラバラになった状態を「スパゲティ」と呼びます。処理の行き先があちらこちらに飛んで、どの処理結果から次の処理へと進むのかが見えなくなった状態を、フォークに絡んでもつれたパスタのイメージに重ねた訳です。

ちなみに、クリント・イーストウッドやジュリアーノ・ジェンマらで有名になったイタリア製の西部劇を日本では「マカロニ・ウェスタン」と呼びますが、本当は「スパゲティ・ウェスタン(Spaghetti western)」です。当時の日本ではスパゲティよりマカロニの方が一般に知られていたことと、音的に発音しやすかったことなどもあってスパゲティがマカロニに化けてしまったようです。

「マカロニ」と言えば、懐かしの刑事ドラマ「太陽にほえろ!」(日本テレビ系列)で萩原健一が演じた刑事を思い出してしまいます。上司は故・石原裕次郎演じる藤堂俊介係長。石原裕次郎と言えば日活黄金時代の大スターで、ニックネームはタフガイ。そのライバルはマイトガイこと小林 旭。小林 旭と言えば、ギターを抱えて馬に乗り拳銃の抜き打ちをやったりする無国籍映画「渡り鳥シリーズ」(斉藤武市監督)。このシリーズは和製西部劇の趣を呈していたため『ウドン・ウェスタン』と呼ばれました。

え、一体何の話をしてるのかって? スパゲティはフォークで持ち上げると絡んで訳が分からなくなるけれど、コシの強い讃岐うどんはお箸でつまむときれいな平行線状に揃うので、『うどんプログラム』っていうのはひょっとしてよいプログラムのことなのかな? なんて……。