* a4_d0006: ラベル計算しかしないアセンブラについて -(by [[K]], 2026.05.14) ** (1) -プリプロセッサ関数でアセンブラを作ろうと思ったら、ラベル計算が必要で、そこだけは #define で作ることはできないから、ラベル計算だけをするアセンブラを作ったよ、という話がありました。 -その「ラベル計算だけをするアセンブラ」っていったいどんなものですか?と聞かれたので、その解説を書きます。 ** (2) -まずラベル計算が一切ない場合、 DB(dataByte)、DW(dataWord)、DD(dataDoubleword)の命令があればアセンブラは問題なくできるでしょう。DBは1バイト、DWは2バイト、DDは4バイトです。 -まあプリプロセッサ機能はもはや空気のように使えるので、 #define DW(i) DB((i)&0xff); DB(((i)>>8)&0xff) #define DD(i) DW((i)&0xffff); DW(((i)>>16)&0xffff) -という2行をアセンブラ変換用のヘッダファイルに書き足しておけば、もはや DB() だけあれはそれ以外は作る必要がない、とも言えます。 -DB() 命令を検出したら、かっこの中の式を計算して、それを char 配列に順番に書いていけばいいだけです。そんなアセンブラでよければ、10行ほどでできるでしょう(式の計算はライブラリにそういう関数があるので丸投げすればいいです)。 ** (3) -x86のアセンブラには、 JMP 命令があります。これは goto みたいなものですが、この時にアドレス計算が必要になります。 LABEL(lp0); INC(EAX); JMP(lp0); -例えばこんな感じです。ここでは INC(EAX); を無限に繰り返すループになっています。 -LABEL() 命令は、 lp0: の代用表記です。プリプロセッサが扱いやすい形式にするためにこうなっています。 -これが変換されると、以下のようになります。 LBL(4); DB(0x40); DB(0xE9); DD_L(4, 1, -4); -この DD_L() というのは「ラベル計算付きの DD 命令」です。(ラベル番号4の値)から(ラベル番号1の値)を引いてさらに-4を加えて、その計算値を DD で書き込みます。 -まずラベルlp0は、適当な整数値に変換されます。これはプリプロセッサの拡張機能として enum 機能があるので簡単に実現できます。 #defineX lp0 defEnum(0) #defineX lp1 defEnum(0) #defineX skp0 defEnum(0) -これで lp0 は 4 になり、 lp1 は 5 になり、 skp0 は 6 になるのです。これがあるので「ラベル計算しかしないアセンブラ」はラベル名管理をしなくてよくなり、ラベルはすべてラベル番号で管理します。 -これで(たとえば) lp0 は 4 になり、 lp1 は 5 になり、 skp0 は 6 になるのです。これがあるので「ラベル計算しかしないアセンブラ」はラベル名管理をしなくてよくなり、ラベルはすべてラベル番号で管理します。 -DD_L() 命令で出てくる(ラベル番号1)は特別な意味を持っていて、それは現在位置を指し示すラベルなのです。 NASM 的に言えば $ のことです。 -だから DD_L(4, 1, -4); は相対ジャンプのためのオフセット値計算になっています。 -なお、 LBL() 命令は、ラベル宣言がここにあったということを示しているだけなので、この命令自体は何も出力しません。 * こめんと欄 #comment