GAS 是 GNU 汇编器,GCC 依赖于它。
在您找到 GCC 的同一个地方可以找到它,在 binutils 包中。binutils 的最新版本可以从 http://sources.redhat.com/binutils/ 获取。
因为 GAS 的发明是为了支持 32 位 unix 编译器,它使用了标准的 AT&T 语法,这非常类似于标准 m68k 汇编器的语法,并且是 UNIX 世界的标准。这种语法既不比 Intel 语法差,也不比它好。它只是不同。当您习惯它之后,您会发现它比 Intel 语法更规范,虽然有点枯燥。
以下是关于 GAS 语法的主要注意事项
寄存器名称以%% 为前缀,因此寄存器是%eax, %dl等等,而不是仅仅是eax, dl等等。这使得可以直接在汇编源代码中包含外部 C 符号,而没有任何混淆的风险,也不需要丑陋的下划线前缀。
操作数的顺序是源操作数在前,目的操作数在后,这与 Intel 约定(目的操作数在前,源操作数在后)相反。因此,在 Intel 语法中是mov eax,edx(将寄存器edx的内容移动到寄存器eax)在 GAS 语法中将是mov %edx,%eax.
操作数大小被指定为指令名称的后缀。后缀是b表示(8 位)字节,w表示(16 位)字,以及l表示(32 位)长字。例如,上述指令的正确语法应该是movl %edx,%eax。然而,gas 并不要求严格的 AT&T 语法,因此当大小可以从寄存器操作数中推断出来时,后缀是可选的,否则默认为 32 位(并发出警告)。
立即数操作数用$$ 前缀标记,如addl $5,%eax(将立即数长字值 5 加到寄存器%eax).
缺少操作数前缀表示它是内存内容;因此movl $foo,%eax将变量foo的内容移动到寄存器%eax的地址放入,但是movl foo,%eaxfoo的内容移动到寄存器%eax.
将变量索引或间接寻址是通过将索引寄存器或间接内存单元地址括在括号中来完成的,如testb $0x80,17(%ebp)(测试从).
%ebp
注意:有一些程序可以帮助您在 AT&T 和 Intel 汇编器语法之间转换源代码;其中一些能够执行双向转换。GAS 在 TeXinfo 格式中有全面的文档,至少在源代码发行版中附带。浏览提取的.info页面,可以使用 Emacs 或任何其他工具。GAS 源代码包中曾经有一个名为 gas.doc 或 as.doc 的文件,但它已合并到 TeXinfo 文档中。当然,如有疑问,最终的文档是源代码本身!您特别感兴趣的部分是
Machine Dependencies::i386-Dependent:同样,Linux(操作系统内核)的源代码也是极好的例子;请查看linux/arch/i386/下的以下文件, kernel/*.S, boot/compressed/*.S.
math-emu/*.S
如果您正在编写某种语言、线程包等,您不妨看看其他语言(OCaml、Gforth 等)或线程包(QuickThreads、MIT pthreads、LinuxThreads 等)或其他东西是如何做的。
3.2.3. Intel 语法好消息是,从 binutils 2.10 版本开始,GAS 也支持 Intel 语法。可以使用.intel_syntax
3.2.4. 16 位模式Binutils (2.9.1.0.25+) 现在完全支持 i386 PC 上的 16 位模式(寄存器和寻址)。使用.code16和.code32
来在汇编模式之间切换。此外,一些人(包括 oskit 作者)使用的一个巧妙技巧是强制 GCC 生成 16 位实模式的代码,使用内联汇编语句asm(".code16\n")
3.2.5. 宏支持GAS 包含一些宏功能,这在 texinfo 文档中有详细说明。此外,虽然 GCC 识别.s文件作为发送到 GAS 的原始汇编代码,但它也识别.S
文件作为在馈送到 GAS 之前通过 CPP 管道传输的文件。再次强调,请查看 Linux 源代码以获取示例。GAS 也有 GASP (GAS 预处理器),它向 GAS 添加了所有常用的宏汇编技巧。GASP 与 GAS 一起包含在 GNU binutils 存档中。它像 和 一样作为过滤器工作。我对细节一无所知,但它附带了自己的 texinfo 文档,您可能想浏览它 (info gasp),打印,理解。带有 GASP 的 GAS 看起来像一个常规的宏汇编器。