2009年10月08日
gas のインテル構文
twitter で gas の構文は理解しにくいと hmori さんがつぶやいていたのを見て、意外と知られて無さそうなので書きます。
x86 と x86-64 において、gas と GCC が出力するアセンブリコードのデフォルト構文は AT&T 構文と呼ばれる UNIX アセンブラの伝統的な構文です。プログラミングの力を生み出す本や、ふつうのコンパイラをつくろうなど、最初から一貫して AT&T 構文を元にアセンブリプログラミングを解説している書籍も無いことは無いのですが、確かにintel のマニュアルの構文とは引数の順番などが異なるので、慣れないと混乱の元になるのではないかと思います。
また、%レジスタや$即値などの独特のプリフィクスが大量に付くので、見た目が少しゴチャゴチャするようにも感じます。(movl などの b/w/l のように、データ長を指定するサフィックスも便利と言えば便利なのですが、区切りが紛らわしい気もします。サフィックスを付けるならば、mov.l のように区切りがある方が、個人的には好みです。ちょっと脱線しました。)
実は gas (GNU Assembler) は、バージョン 2.10 から、インテル構文 (intel syntax) もサポートしています。
x86 と x86-64 において、gas と GCC が出力するアセンブリコードのデフォルト構文は AT&T 構文と呼ばれる UNIX アセンブラの伝統的な構文です。プログラミングの力を生み出す本や、ふつうのコンパイラをつくろうなど、最初から一貫して AT&T 構文を元にアセンブリプログラミングを解説している書籍も無いことは無いのですが、確かにintel のマニュアルの構文とは引数の順番などが異なるので、慣れないと混乱の元になるのではないかと思います。
また、%レジスタや$即値などの独特のプリフィクスが大量に付くので、見た目が少しゴチャゴチャするようにも感じます。(movl などの b/w/l のように、データ長を指定するサフィックスも便利と言えば便利なのですが、区切りが紛らわしい気もします。サフィックスを付けるならば、mov.l のように区切りがある方が、個人的には好みです。ちょっと脱線しました。)
実は gas (GNU Assembler) は、バージョン 2.10 から、インテル構文 (intel syntax) もサポートしています。
GCC も、3.0 からインテル構文のアセンブリを出力するオプションをサポートしています。
.intel_syntax ディレクティブと、noprefix ディレクティブを指定することによりインテル構文に切り替えることができます。これはインラインアセンブラの中でも有効です。
Microsoft Visual C++ が出力するmasm (Microsoft Macro Assembler) 用のコードや、nasm (Netwide Assembler) はインテル構文なので、そちらに慣れている人や、コードを移植する際(構文は同じでも、ディレクティブや擬似命令は異なるので、当然そのままでは gas のコードはアセンブルできません)にも有用だと思います。
インテル構文と AT&T 構文(というよりもむしろ、各アセンブラの文法)の相違点については、以下の URL がよくまとまっています。
「Linux のアセンブラー: GAS と NASM を比較する」
http://www.ibm.com/developerworks/jp/linux/library/l-gas-nasm.html
.intel_syntax ディレクティブと、noprefix ディレクティブを指定することによりインテル構文に切り替えることができます。これはインラインアセンブラの中でも有効です。
$ cat test.c
int main()
{
return (0);
}
$ gcc test.c -S -o -
.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
call ___main
movl $0, %eax
movl %ebp, %esp
popl %ebp
ret
$ gcc test.c -S -masm=intel -o -
.file "test.c"
.intel_syntax noprefix
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
push ebp
mov ebp, esp
and esp, -16
call ___main
mov eax, 0
mov esp, ebp
pop ebp
ret
(-o - で標準出力に直接アセンブリコードを出力しています。)Microsoft Visual C++ が出力するmasm (Microsoft Macro Assembler) 用のコードや、nasm (Netwide Assembler) はインテル構文なので、そちらに慣れている人や、コードを移植する際(構文は同じでも、ディレクティブや擬似命令は異なるので、当然そのままでは gas のコードはアセンブルできません)にも有用だと思います。
インテル構文と AT&T 構文(というよりもむしろ、各アセンブラの文法)の相違点については、以下の URL がよくまとまっています。
「Linux のアセンブラー: GAS と NASM を比較する」
http://www.ibm.com/developerworks/jp/linux/library/l-gas-nasm.html