我并没有试图提示英特尔与AT& T战争(无论如何,现在他们都支持英特尔语法)或者问哪一个本身“更好”,我只是想知道实际的差异。选择其中一个。
基本上,当我几年前拿起一些基本的x86组件时,除了我正在阅读的那本书之外,我毫无理由地使用NASM - 这让我坚定但不由自主地进入了NASM阵营。从那时起,我使用汇编的原因很少,所以我没有机会尝试GAS。
请记住,它们都支持Intel语法(我个人更喜欢),理论上至少应该生成相同的二进制文件(我知道它们可能不会,但意思不应该改变),是什么赞成其中一个的理由?
是命令行选项吗?宏?非助记符关键字?或其他什么?
谢谢:)
答案 0 :(得分:21)
英特尔语法:mov eax,1(指令目的地,来源)
AT& T语法:movl $ 1,%eax(指令来源,目的地)
英特尔语法非常自我解释。在上面的例子中,移动的数据量是从寄存器的大小推断的(在eax的情况下是32位)。使用的寻址模式是从操作数本身推断出来的。
在AT& T语法方面存在一些怪癖。首先,请注意l
指令末尾的mov
后缀,这代表long
并表示32位数据。其他说明后缀包括
w
代表一个单词(16位 - 不)与您的单词大小混淆
CPU!),q
表示四字(64位),b
表示单字节。虽然并非总是需要,但通常您会看到使用AT& T语法的汇编代码明确说明指令操作的数据量。
当涉及源和目标操作数上使用的寻址模式时,需要更明确。 $
表示immediate
寻址,就像使用指令本身中的值一样。在上面的示例中,如果它是在没有此$
的情况下写入的,则会使用direct
寻址,即CPU将尝试获取内存地址1处的值(这很可能会导致分段错误)。 %
表示register
寻址,如果您在上面的示例中未包含此内容eax
将被视为symbol
,即标记的内存地址,这将超过可能会在链接时导致undefined reference
。因此强制性是明确关于两者源和目标操作数上使用的寻址模式。
指定内存操作数的方式也不同:
英特尔:[基本寄存器+索引*索引大小+偏移量]
AT& T :偏移量(基址寄存器,索引,索引大小)
英特尔语法使得查找内存地址的计算变得更加清晰。使用AT& T语法,结果是相同的,但您应该知道正在进行的计算。
理论上,至少应该产生相同的二进制
这完全取决于您的工具链。
赞成其中一个的原因是什么?
个人偏好当然,在我看来,归结为你在寻址内存时感觉更舒服的语法。你更喜欢AT& T语法的强制显式吗?或者你更喜欢你的汇编程序为你找出这个低级细节?
是命令行选项吗?宏?非助记符关键字?
这与汇编程序(GAS,NASM)本身有关。再次,个人偏好。
答案 1 :(得分:20)
NASM实际上使用了自己的英特尔语法变体,与英特尔官方文档中使用的MASM语法不同。操作码名称和操作数顺序与英特尔相同,因此乍一看说明看起来相同,但任何重要程序都会有差异。例如,对于MASM,MOV ax, foo
使用的指令取决于foo
的类型,而NASM没有类型,这总是汇集到移动立即指令。当无法确定操作数的大小时,MASM需要使用类似DWORD PTR
的内容,而NASM使用DWORD
表示相同的事情。除指令助记符和基本操作数格式和排序之外的大部分语法都不同。
在功能方面,NASM和GAS几乎相同。两者都有汇编宏设施,尽管NASM更广泛,更成熟。许多GAS源代码文件使用C预处理器而不是GAS自己的宏支持。
两个汇编程序之间的最大区别是它们支持16位代码。 GAS对定义x86段没有任何支持。使用GAS,您仅限于创建简单的单段16位二进制映像,基本上只是启动扇区和.COM文件。 NASM完全支持段并支持OMF格式的目标文件,您可以使用合适的链接器创建分段的16位可执行文件。
除了OMF目标文件格式外,NASM还支持GAS不具备的多种格式。 GAS通常只支持运行它的机器的本机格式,基本上是ELF,PE-COFF或MACH-O。如果您想支持不同的格式,您需要构建一个"交叉编译"该格式的GAS版本。
另一个值得注意的差异是GAS支持创建DWARF和Windows 64位展开信息(Windows x64 ABI要求的后者),而使用NASM,您可以创建创建部分并自行填写数据。
答案 2 :(得分:0)
为什么不检查此post?
NASM和GAS之间最大的区别之一是语法。 GAS使用AT&T语法,这是一种相对古老的语法,专用于GAS和某些较旧的汇编程序,而NASM使用Intel语法,该语法受大多数汇编程序(例如TASM和MASM)支持。 (现代版本的GAS确实支持名为.intel_syntax的指令,该指令允许在GAS中使用Intel语法。)
涵盖范围:
一种好的做法是在两种方言中都写hello_world,并具有具体的感觉。