GNU Assembler

GNU Assemblerのシンタックス

通常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双方の変更が可能となります。

文法の主な違い
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

Instruction Naming

GNU Assemblerのインストラクションのニーモニックには、オペランドのサイズにより、ニーモニックの最後に1文字の修飾子(サフィックス)が付くものがあります。それらのサフィックスはオペランドのサイズにより、'b'(byte[8bit]),'w'(word[16bit]),'l'(long[32bit]),q(quadruple word[64bit])を付加します。

サフィックス一覧
suffixessize
bbyte(8bit)
wword(16bit)
llong(32bit)
qquadruple word(64bit) [x86-64 only]

これらのサフィックスを省略した場合、GNU Assemblerはdestination registerのサイズに従い、自動的にサフィックス付加する。例えば、

サフィックスが省略された場合、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意味
blfrom Byte to Long
bwfrom Byte to Word
wlfrom Word to Long
bqfrom Byte to Quadruple word
wqfrom Word to Quadruple word
lqfrom Long to Quadruple word

それ以外の違いは、下記のようになります。

符合/ゼロ拡張命令のサフィックス一覧2
AT&TIntel意味
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)

Register Naming

レジスタ オペランドには、常に'%'が付加されます。

Intel 80386 register 一覧
SizeRegister 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 一覧
SizeRegister 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

Instruction Prefixes

インストラクションにプリフィックスを指定することにより、string命令の繰り返し、セクション・オーバーライド、バス・ロック・オペレーション、オペランドとアドレスのサイズを変更する等を行うことができます。

Memory References

Intelシンタックスでは、メモリの間接参照は、section:[base + index*scale + disp] となります。

AT&Tシンタックスでは、section:disp(base, index, scale) となります。

各パラメータの意味は

間接参照の例
AT&TIntel意味
-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への絶対ジャンプ

参考資料

Linuxにおけるx86インライン・アセンブラー
アセンブラでの高速化
Last modified: Thu Jan 24 15:37:33 2008 JST