通常Intel系のアセンブラは、Intel Syntaxと呼ばれる文法を使用していますが、GNU AssemblerはAT&T Syntaxを使用しています。そして、AT&T System V/386アセンブラの文法は、インテル アセンブラの文法と非常に異なっています。BSD kernelのアセンブラ部分はAT&T Syntaxが使われているので、これらの違いについて説明しておきます。
なお現在の、GNU AssemblerはIntel Syntaxもサポートしており、Intel ModeとAT&T Mode双方の変更が可能となります。
- '.intel_syntax'ディレクティブを指定する事によりIntel Mode
- '.att_syntax'ディレクティブを指定する事によりAT&T Mode
文法の主な違い
|
AT&Tの即値オペランドには'$'が付く。
|
| Intel |
Opcode imm
|
Ex. push 4
|
| AT&T |
OPcode $imm
|
Ex. push $4
|
|
AT&Tのレジスタには'%'が付く。
|
| Intel |
reg
|
Ex. eax
|
| AT&T |
%reg
|
Ex. %eax
|
|
AT&TとInteのシンタックスが使用する、source/destination オペランドの順番は逆になっている。
|
| Intel |
OPcode SRC,DEST
|
Ex. add eax,4
|
| AT&T |
OPcode DEST,SRC
|
Ex. addl $4,%eax
|
|
オペランドがbyte(8bit)/word(16bit)/long(32bit)/quadruple word(64bit)のいずれであるかによって、命令の接尾部にb/w/l/qが付く。
|
| Intel |
OPcode OP1,OP2
|
Ex. mov al,byte ptr label
|
| AT&T |
OPcode[bwlq] OP1,OP2
|
Ex. movb label,%al
|
|
即値形式でのロングjump/callは、`lcall/ljmp $section, $offset'となる。また、far return 命令は `lret $imm'となる。
|
| Intel |
call/jmp far section,offset
|
Ex. call far BOOTBIOS:1f
|
| AT&T |
lcall/ljmp $section,$offset
|
Ex. lcall $BOOTBIOS,$1f
|
GNU Assemblerのインストラクションのニーモニックには、オペランドのサイズにより、ニーモニックの最後に1文字の修飾子(サフィックス)が付くものがあります。それらのサフィックスはオペランドのサイズにより、'b'(byte[8bit]),'w'(word[16bit]),'l'(long[32bit]),q(quadruple word[64bit])を付加します。
サフィックス一覧
| suffixes | size |
| b | byte(8bit) |
| w | word(16bit) |
| l | long(32bit) |
| q | quadruple word(64bit) [x86-64 only] |
これらのサフィックスを省略した場合、GNU Assemblerはdestination registerのサイズに従い、自動的にサフィックス付加する。例えば、
mov %ax, %bxとmovw %ax, %bxは同等である。
mov $1, %ebxとmovl $1, %ebxは同等である。
サフィックスが省略された場合、longサイズと仮定する、AT&T Unix assemblerとの互換性がないことに注意してください。
上記の規則は、ほとんどの命令に適合出来ますが、いくつかの命令で例外があります。
符合拡張やゼロ拡張の命令の場合、destとsrcのサイズが異なるAT&T シンタックスでは2つのサフィックスを使うことによってこれを解決しています。AT&Tの符合拡張とゼロ拡張命令のベースネームは'movs[suffixes]'(intelは'movsx')と'movz[suffixes]'(intelは'movzx')の形式を取ります。
例えば、alレジスタの内容を符合拡張してedxレジスタに代入する場合、`movsbl %al, %edx'となります。この場合のサフィックス'bl'は、'from Byte to Long'の意味を持ちます。
符合/ゼロ拡張命令のサフィックス一覧1
| suffixes | 意味 |
| bl | from Byte to Long |
| bw | from Byte to Word |
| wl | from Word to Long |
| bq | from Byte to Quadruple word |
| wq | from Word to Quadruple word |
| lq | from Long to Quadruple word |
それ以外の違いは、下記のようになります。
符合/ゼロ拡張命令のサフィックス一覧2
| AT&T | Intel | 意味 |
| cbtw(Convert Byte To Word) | cbw |
%alの符合を%ax拡張する。 |
| cwtl(Convert Word To Long) | cwde |
%axの符合を%eaxに拡張する。 |
| cwtd(Convert Word To Double) | cwd |
%axの符合を%dx:%axに拡張する。 |
| cltd(Convert Long To Double) | cdq |
%eaxの符合を%edx:%eaxに拡張する。 |
| cltq(Convert Long To Quad) | cdqe |
%eaxの符合を%raxに拡張する。(x86-64 only) |
| cqto(Convert Quad To Octuple) | cdo |
%raxの符合を%rdx:%raxに拡張する。(x86-64 only) |
レジスタ オペランドには、常に'%'が付加されます。
Intel 80386 register 一覧
| Size | Register Name |
| 32-bit registers |
%eax(the accumulator), %ebx, %ecx, %edx, %edi,
%esi, %ebp(the frame pointer), %esp(the stack pointer)
|
| 16-bit registers |
%ax, %bx, %cx, %dx, %di, %si, %bp, %sp
|
| 8-bit registers |
%ah, %al, %bh, %bl, %ch, %cl, %dh, %dl
|
| section registers |
%cs(code section), %ds(data section), %ss(stack section), %es, %fs, %gs.
|
| processor control registers |
%cr0, %cr2, %cr3
|
| debug registers |
%db0, %db1, %db2, %db3, %db6, %db7
|
| test registers |
%tr6, %tr7
|
| floating point registers |
%st(0), %st(1), %st(2), %st(3), %st(4), %st(5), %st(6), %st(7)
|
| MMX registers |
%mm0, %mm1, %mm2, %mm3, %mm4, %mm5, %mm6, %mm7.
|
| SSE registers |
%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7
|
AMD x86-64 architectureは下記のように拡張されます。
AMD x86-64 architecture register 一覧
| Size | Register Name |
| 64-bit Registers |
%rax(the accumulator), %rbx, %rcx, %rdx, %rdi, %rsi,
%rbp(the frame pointer), %rsp(the stack pointer)
|
| extended registers |
%r8 -- %r15
|
| 32-bit extended registers |
%r8d -- %r15d
|
| 16-bit extended registers |
%r8w -- %r15w
|
| 8-bit extended registers |
%r8b -- %r15b
|
| 8-bit registers |
%sil, %dil, %bpl, %spl
|
| debug registers |
%db8 -- %db15
|
| SSE registers |
%xmm8 -- %xmm15
|
インストラクションにプリフィックスを指定することにより、string命令の繰り返し、セクション・オーバーライド、バス・ロック・オペレーション、オペランドとアドレスのサイズを変更する等を行うことができます。
- セクションはプレフィックス"cs","ds","ss","es","fs","gs"が優先する。
そして、メモリ参照のために section:memory-operand形式を指定することによって、
これらは自動的に加算される。
- オペランド・サイズ・プリフィックス"data16"は、32bitオペランドを16bitオペランド
に変更する
アドレス・サイズ・プリフィックス"add16"は、32bitアドレスを16bitアドレスに変更する。
"data32","add32"は16bitオペランド/アドレス(".code16"directiveを指定していた場合)を
32bitオペランド/アドレスに変更する。
- bus lock prefixである"lock"は、命令実行中に割込みが入ることを制限する。
- "wait" prefixは、coprocessorの完了まで、現在の命令を待たせる。
- `rep',`repe',`repne' prefixをstring命令に加えることにより%ecxレジスタ回数分、その命令を繰り返す。
Intelシンタックスでは、メモリの間接参照は、section:[base + index*scale + disp] となります。
AT&Tシンタックスでは、section:disp(base, index, scale) となります。
各パラメータの意味は
- base,indexは32bit base register、32bit index register
- dispディスプレースメント
- scale 1,2,4,8のいずれかの値をとる。省略時は1になる。これは(index*scale)の関係となる。
間接参照の例
| AT&T | Intel | 意味 |
| -4(%ebp) | [ebp - 4] |
baseは"%ebp",dispは"-4"になっている。indexとscaleは省略されている。
セクションは、"%ebp"で参照するときのデフォルトのレジスタ、"%ss"が使用される。
|
| foo(,%eax,4) | [foo + eax*4] |
indexは"%eax",dispは"foo",scaleは"4"になって、それ以外は省略されている。
セクションは、デフォルトのレジスタ、"%ds"が使用される。
|
| foo(,1) | [foo] |
dispは"foo",indexは省略されているが1になっている。
|
| %gs:foo | [gs]:[foo] |
セッションは"%gs"で示され、オフセットは変数"foo"の内容で示される。
|
これ以外に、絶対番地へのジャンプ"jmp/call"には、'*'をアドレス値につける。
| jmp 0xabcd |
セッションに対する、相対ジャンプ |
| jmp *0x1234abcd |
0x1234abcdへの絶対ジャンプ |