NASM の基本

NASM の基本
ここからは、NASM における、基本的な構文を説明していきます。

; コメント
LABEL: 命令 オペランド[, ...]

  • セミコロン (;) から行末までは、コメント。
  • 行がバックスラッシュ (\) で終わる場合、次の行に続く。
  • どの位置に、どれだけの空白があってもよい。
  • ラベルやシンボル名の大文字小文字は区別されるが、命令などの大文字小文字は区別されない。
  • ラベルは、その位置のアドレスを、わかりやすい名前で定義して、参照できるようにするためのもの。
    ジャンプ先、データの位置、関数名などとして使われる。
  • ラベルの後にコロン (:) を付けるのは、オプション。
    ':' は、あってもなくても良いが、基本的には付けたほうがわかりやすい。
  • ラベルで有効な文字は、「アルファベット」「数字」「_ $ # @ ~ . ?」。
    ただし、最初の文字として使えるのは、「アルファベット」と「.」のみ。
    ラベルの最大長は、4095 文字。
  • 予約語とラベル名を明確に区別するため、ラベルの先頭には '$' を付けることができる。
    例えば、eax という名前のラベルを、定義または参照したい場合、$eax と記述する。
ローカルラベル
ラベル名の先頭にピリオド (.) が付いている場合、ローカルラベルとして扱われます。

ローカルラベルは、一つ前の、ローカルではないラベルと関連付けられます。

label1:
  ...
.loop:
; label1 を基準とする
  ...
label2:
  ...
.loop:
; label2 を基準とする

上記の場合、label1 の後の .loop は、一つ前の非ローカルラベル label1 と関連付けられます。
同じように、label2 の後の .loop は、一つ前の非ローカルラベル label2 と関連付けられます。

ローカルラベルを使わない場合、1つのソースファイル内のラベルは、すべて異なる名前にする必要がありますが、ローカルラベルを使うと、同じソースファイル内で、同じラベルを複数回記述することができます。
ローカルラベルの参照
ローカルラベルは、実際には、「一つ前の非ローカルラベル」と「ローカルラベル」の名前を結合したラベルとして定義されます。

上記の例では、「label1.loop」「label2.loop」のラベルが定義されることになります。

そのため、任意の場所から、任意のローカルラベルを参照したい場合は、結合したラベル名を指定します。

jmp label1.loop
数値
オペランド (命令に対して指定するレジスタや値) やデータ定義で、任意の数値を指定する場合、以下の接尾語や接頭語を付けて表現することができます。
これらの接尾語や接頭語がない場合は、10進数になります (データ定義で '.' が含まれる場合は、常に浮動小数点数になります)。

接尾語
(数値の後)
h,H,x,X = 16進数
d,D,t,T = 10進数
q,Q,o,O = 8進数
b,B,y,Y = 2進数

※16進数で、先頭文字がアルファベットの場合は、シンボルとして認識されます。
その場合、先頭に 0 を付けるか、接頭語を使うこと。
接頭語
(数値の前)
0x,0h,$ = 16進数
0d,0t = 10進数
0o,0q = 8進数
0b,0y = 2進数

※'$' の場合、次の文字は数字であること。
※C 言語とは異なり、接頭語が 0 のみの場合は、8進数として扱わない。

なお、長い文字列を分割するために、任意の位置にアンダースコア (_) を入れることができます。

255
53h
FFh  ; FFh というシンボルになる
0FFh ; 問題ない
1000_1011b
0xB2
0o777
文字
文字定数は、シングルクォート ('...')、ダブルクォート ("...")、バッククォート (`...`) のいずれかで囲まれた 1〜8 文字を、1つの整数として扱います。
※いわゆる通常の文字列とは異なり、整数として表現されることに注意してください。

'5' -> 0x35
'ab' -> 0x6261
'abcd' -> 0x64636261

リトルエンディアンとして、最初の文字が最下位バイトに格納されるので、文字の順番とは逆順で数値が並びます。
ただし、メモリに格納すると、メモリ上では元の文字順で並びます。

64bit 整数まで扱えるので、最大8文字 (8 byte) を指定できます。

例えば、ビットマップファイル (BMP) の先頭 2 byte は "BM" になっているので、ファイルから 2 byte の整数として 16bit 値を読み込んで、"BM" と比較したい、という場合に使えます。

cmp ax, 'BM'
エスケープ
バッククォート (`...`) で囲まれている場合は、バックスラッシュ (\) によるエスケープを使うことができます。

\'(')
\"(")
\`(`)
\\(\)
\?(?)
\aBEL (ASCII 7)
\bBS (ASCII 8)
\tTAB (ASCII 9)
\nLF (ASCII 10)
\vVT (ASCII 11)
\fFF (ASCII 12)
\rCR (ASCII 13)
\eESC (ASCII 27)
\3773文字までの8進数
\xFF2文字までの16進数
\u12344文字の16進数 Unicode (UTF-8 変換)
\U123456788文字の16進数 Unicode (UTF-8 変換)

Unicode は、指定された1文字を、UTF-8 の複数バイトに変換します。
浮動小数点数
以下の特殊演算子を使うと、浮動小数点数で記述された値を、各フォーマットのバイナリ値に変換することができます。

Dx 疑似命令でのデータ定義時には、あらかじめサイズが明示されているので、そのまま浮動小数点数を記述することができますが、命令のオペランドとして値を指定する場合は、この特殊演算子を使う必要があります。

__?float8?__8bit
__?float16?__16bit 半精度
__?bfloat16?__仮数部が削除された、32bit 単精度の圧縮バージョン
__?float32?__32bit 単精度 (float)
__?float64?__64bit 倍精度 (double)
__?float80m?__x87 80bit の仮数部 (64bit)
__?float80e?__x87 80bit の指数部 (16bit)
__?float128l?__128bit 浮動小数点の下位 64bit
__?float128h?__128bit 浮動小数点の上位 64bit

mov rax, __?float64?__(1.234) ; mov rax,0x3ff3be76c8b43958
movq xmm0, rax

特殊演算子内で以下のトークンを使うと、無限大や NaN の値を生成できます。

__?Infinity?__
__?QNaN?__
__?SNaN?__
__?NaN?__ (QNaN と同じ)