为什么我要使用 NASM 而不是 GNU 汇编程序 (GAS)?

Why would I use NASM over GNU Assembler (GAS)?

当 GAS 支持多种架构而 NASM 只支持 x86 架构时,为什么我要使用 NASM 而不是 GNU 汇编器 (GAS)?我知道存在句法差异,但这并没有让我太在意。

ASM 本质上是不可移植的。只有 GAS 指令对于其他 ISA 是相同的(不是指令甚至注释字符),并且任何给定的 asm 源文件都将用于单个 ISA。 GAS 本身支持多目标其实关系不大,还是要学其他机器。 (一旦你了解了基础知识,这至少不难掌握,但指令语法差异通常更容易)。其他一些用于其他 ISA 的 assemblers 使用 NASM 风格的 dbdd 数据伪指令,其他人使用 Unix 风格的 .byte.long 就像 GAS(或 GAS)。但这很容易适应。

GAS 最初设计用于 assemble 编译器输出;因此,它的错误消息并不总是适合人类使用。 (就清楚它到底不喜欢一条线的什么而言)。 NASM 趋于更好(但绝不是完美的),现代 GAS 通常也不错;一些主要项目(如 glibc 和 Linux)有手写的 GAS 源文件,因此肯定有人使用它。

NASM有宏语言(https://www.nasm.us/doc/nasmdoc4.html) that in some ways is easier to use for complex stuff than GAS's .macro macros。(虽然在GAS中使用CPP宏很常见)。

对于微基准测试(这些天手动使用 asm 的少数原因之一),NASM 有一个我不知道如何使用的功能在 GAS 中同样容易:times 重复一行。 %rep 重复一个块也很有用。 GAS 的 .rept 可以做到这一点,但如果你想改变方块(例如展开并执行 [rdi+0] / [rdi+4] / ...),NASM 更好。在 GAS 中,您可以使用递归宏,该宏使用较小的 arg 调用自身,但是 NASM 允许 %assign%rep.

中实现计数器
    times 10  imul eax,eax        ; repeat this line 10 times

 %rep 10                       ; repeat this block 10 times
    add  eax, ecx
    add  ecx, eax
 %endrep

NASM 对于多字符常量作为数字有非常好的语法,例如mov rax, 'abcdefgh' / push rax 以源代码顺序在堆栈中生成这 8 个 ASCII 字符。 GAS 不能做任何等效的事情;您需要使用原始数字或 'h'<<56 | 'g'<<48 | ...

之类的东西

NASM 可以 assemble 平面二进制文件而不需要复杂的链接器 + 链接器脚本。大多数只与 16 位引导加载程序相关,但可能与 shellcode 有关。

直到最近,GAS 有一些不好的东西,比如 add [rdi], 1234 默默地默认为 dword 操作数大小,而不是警告你它对于 mov 以外的指令是不明确的。最近的 GAS 解决了这个问题;现在这是一个错误,就像 NASM.


NASM 的语法与 [] 是 100% 一致的 - 存在括号 总是 表示内存操作数,不存在意味着 永远不会 内存操作数。 (为了清楚我的意思,LEA 接受一个内存操作数但不从中加载。)AT&T 语法也很容易区分($ 或不是立即数或内存之间的区别),但是 GAS .intel_syntax noprefix 取决于交易品种的声明方式add eax, foobar 可以是 add eax, imm32add eax, [disp32]。更糟糕的是,这取决于 foobar 是在使用它的指令之前还是之后用 equ= 声明的,除非你使用 OFFSET 即使你稍后做foobar = 42!!! .

Intel 语法是 NASM 的主要且唯一的模式,因此您可以轻松地在 Intel 或 AMD 的手册中查找说明。 .intel_syntax noprefix 是 GAS 的次要功能,其记录不如其 AT&T。除了上面的歧义外,它确实工作得很好。

有时 GNU 工具甚至在 Intel 语法模式下(如 objdump -d -Mintel)仍然遵循 AT&T 语法错误交换某些形式的 x87 指令,如 fdiv 与 fdivr。如果你想使用 x87,请尽可能避免使用 GAS。请参阅 GAS 手册中的 9.16.17 AT&T Syntax bugs。我认为现代 objdump 现在可能“做对了”,但如果我只使用 GAS + binutils,我就不会有我相信不会被愚蠢的 AT&T 实现错误破坏的东西,而 GAS 必须与之兼容。在 x87 指令之外完全不相关,幸运的是现在大部分时间都不相关。