NASM の基本
ここからは、NASM における、基本的な構文を説明していきます。
; コメント LABEL: 命令 オペランド[, ...]
- セミコロン (;) から行末までは、コメント。
- 行がバックスラッシュ (\) で終わる場合、次の行に続く。
- どの位置に、どれだけの空白があってもよい。
- ラベルやシンボル名の大文字小文字は区別されるが、命令などの大文字小文字は区別されない。
- ラベルは、その位置のアドレスを、わかりやすい名前で定義して、参照できるようにするためのもの。
ジャンプ先、データの位置、関数名などとして使われる。 - ラベルの後にコロン (:) を付けるのは、オプション。
':' は、あってもなくても良いが、基本的には付けたほうがわかりやすい。 - ラベルで有効な文字は、「アルファベット」「数字」「_ $ # @ ~ . ?」。
ただし、最初の文字として使えるのは、「アルファベット」と「.」のみ。
ラベルの最大長は、4095 文字。 - 予約語とラベル名を明確に区別するため、ラベルの先頭には '$' を付けることができる。
例えば、eax という名前のラベルを、定義または参照したい場合、$eax と記述する。
ローカルラベル
ラベル名の先頭にピリオド (.) が付いている場合、ローカルラベルとして扱われます。
ローカルラベルは、一つ前の、ローカルではないラベルと関連付けられます。
上記の場合、label1 の後の .loop は、一つ前の非ローカルラベル label1 と関連付けられます。
同じように、label2 の後の .loop は、一つ前の非ローカルラベル label2 と関連付けられます。
ローカルラベルを使わない場合、1つのソースファイル内のラベルは、すべて異なる名前にする必要がありますが、ローカルラベルを使うと、同じソースファイル内で、同じラベルを複数回記述することができます。
ローカルラベルは、一つ前の、ローカルではないラベルと関連付けられます。
label1: ... .loop: ; label1 を基準とする ... label2: ... .loop: ; label2 を基準とする
上記の場合、label1 の後の .loop は、一つ前の非ローカルラベル label1 と関連付けられます。
同じように、label2 の後の .loop は、一つ前の非ローカルラベル label2 と関連付けられます。
ローカルラベルを使わない場合、1つのソースファイル内のラベルは、すべて異なる名前にする必要がありますが、ローカルラベルを使うと、同じソースファイル内で、同じラベルを複数回記述することができます。
ローカルラベルの参照
ローカルラベルは、実際には、「一つ前の非ローカルラベル」と「ローカルラベル」の名前を結合したラベルとして定義されます。
上記の例では、「label1.loop」「label2.loop」のラベルが定義されることになります。
そのため、任意の場所から、任意のローカルラベルを参照したい場合は、結合したラベル名を指定します。
上記の例では、「label1.loop」「label2.loop」のラベルが定義されることになります。
そのため、任意の場所から、任意のローカルラベルを参照したい場合は、結合したラベル名を指定します。
jmp label1.loop
数値
オペランド (命令に対して指定するレジスタや値) やデータ定義で、任意の数値を指定する場合、以下の接尾語や接頭語を付けて表現することができます。
これらの接尾語や接頭語がない場合は、10進数になります (データ定義で '.' が含まれる場合は、常に浮動小数点数になります)。
なお、長い文字列を分割するために、任意の位置にアンダースコア (_) を入れることができます。
これらの接尾語や接頭語がない場合は、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つの整数として扱います。
※いわゆる通常の文字列とは異なり、整数として表現されることに注意してください。
リトルエンディアンとして、最初の文字が最下位バイトに格納されるので、文字の順番とは逆順で数値が並びます。
ただし、メモリに格納すると、メモリ上では元の文字順で並びます。
64bit 整数まで扱えるので、最大8文字 (8 byte) を指定できます。
例えば、ビットマップファイル (BMP) の先頭 2 byte は "BM" になっているので、ファイルから 2 byte の整数として 16bit 値を読み込んで、"BM" と比較したい、という場合に使えます。
※いわゆる通常の文字列とは異なり、整数として表現されることに注意してください。
'5' -> 0x35 'ab' -> 0x6261 'abcd' -> 0x64636261
リトルエンディアンとして、最初の文字が最下位バイトに格納されるので、文字の順番とは逆順で数値が並びます。
ただし、メモリに格納すると、メモリ上では元の文字順で並びます。
64bit 整数まで扱えるので、最大8文字 (8 byte) を指定できます。
例えば、ビットマップファイル (BMP) の先頭 2 byte は "BM" になっているので、ファイルから 2 byte の整数として 16bit 値を読み込んで、"BM" と比較したい、という場合に使えます。
cmp ax, 'BM'
エスケープ
バッククォート (`...`) で囲まれている場合は、バックスラッシュ (\) によるエスケープを使うことができます。
Unicode は、指定された1文字を、UTF-8 の複数バイトに変換します。
\' | (') |
---|---|
\" | (") |
\` | (`) |
\\ | (\) |
\? | (?) |
\a | BEL (ASCII 7) |
\b | BS (ASCII 8) |
\t | TAB (ASCII 9) |
\n | LF (ASCII 10) |
\v | VT (ASCII 11) |
\f | FF (ASCII 12) |
\r | CR (ASCII 13) |
\e | ESC (ASCII 27) |
\377 | 3文字までの8進数 |
\xFF | 2文字までの16進数 |
\u1234 | 4文字の16進数 Unicode (UTF-8 変換) |
\U12345678 | 8文字の16進数 Unicode (UTF-8 変換) |
Unicode は、指定された1文字を、UTF-8 の複数バイトに変換します。
浮動小数点数
以下の特殊演算子を使うと、浮動小数点数で記述された値を、各フォーマットのバイナリ値に変換することができます。
Dx 疑似命令でのデータ定義時には、あらかじめサイズが明示されているので、そのまま浮動小数点数を記述することができますが、命令のオペランドとして値を指定する場合は、この特殊演算子を使う必要があります。
特殊演算子内で以下のトークンを使うと、無限大や NaN の値を生成できます。
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 と同じ)