Ell*_*ott 35 x86 assembly gnu-assembler nasm
我并没有试图提示英特尔与AT&T之争(无论如何,现在他们都支持英特尔语法)或者问哪一个本身"更好",我只是想知道选择其中一个的实际差异. .
基本上,当我几年前拿起一些基本的x86组件时,除了我正在阅读的那本书之外,我没有理由使用NASM - 这让我坚定但不由自主地进入了NASM阵营.从那时起,我使用汇编的原因很少,所以我没有机会尝试GAS.
请记住,它们都支持英特尔语法(我个人更喜欢),理论上至少应该生成相同的二进制文件(我知道它们可能不会,但意思不应该改变),有什么理由支持非此即彼?
是命令行选项吗?宏?非助记符关键字?或者是其他东西?
谢谢 :)
una*_*e01 22
英特尔语法: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)本身有关.再次,个人偏好.
Ros*_*dge 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,您可以创建创建部分并自行填写数据.