x86标准是否包含助记符,还是仅定义操作码?
如果它不包括它们,那么对于不同的汇编程序是否有其他标准?
- AT&T型汇编程序将
b
、w
、l
和q
后缀应用于所有助记符,以指示操作数大小。英特尔风格的汇编程序通常用关键字byte
、word
、dword
和qword
来表示这一点 - AT&T型汇编程序识别
cbtw
、cwtl
、cltq
和cqto
,而英特尔型汇编程序则识别与cbw
、cwd
、cdq
和cqo
相同的指令 - AT&T型汇编程序识别
movz??
和movs??
,其中??
是Intel型汇编程序所称的movzx
、movsx
和movsxd
的两个大小后缀 - 一些英特尔风格的汇编程序只将
63 /r
识别为movsxd
,而另一些则将movsx
识别为该指令的变体 - Plan 9风格的汇编程序(比如Go中使用的)非常奇怪,而且在很多方面都有所不同,比如使用摩托罗拉风格的助记符进行条件跳跃
- 从历史上看,为8086的NEC V20克隆提供的NEC汇编程序具有几乎完全不同的助记符。例如,
int
被称为brk
不幸的是;x86标准";写在纸上,定义了CPU成为x86必须满足的所有最低要求。
英特尔的文档非常接近的"x86标准";,但在某些情况下,与现代AMD CPU相比,它在某些方面提供了更强的保证。例如,英特尔保证1/2/4/8字节的原子性,从/到可缓存内存的加载或存储具有任何不跨越缓存线边界的对齐。但AMD只保证不跨越8字节边界的可缓存加载/存储。
为什么在x86上,自然对齐变量上的整数赋值是原子的?引用了英特尔的手册,表明所有的保证都是以";Intel486处理器(以及此后更新的处理器)";担保。没有给出适用于所有x86 CPU(或者更重要的是所有x86-64 CPU)的基线。我认为x86(包括x86-64之前的版本)的实际共享基线是1字节,因为8088。
因此,想要在现代x86-64 CPU上运行的软件不能假设8字节加载/存储的原子性,除非它们真正对齐。我想我们都同意,原子性保证是现代多核x86 CPU的重要组成部分。即使在单个核心上,未缓存MMIO访问的原子性也很重要;现代英特尔和AMD同意这一点,但英特尔再次仅以";Pentium及更高版本的处理器";。隐含地";后来的英特尔处理器";。
也就是说,英特尔的文档确实为每个操作码定义了助记符和寄存器名称。AMD的文档在所有这些方面都与英特尔的一致
请参阅英特尔x86软件开发手册第2卷。仅按说明手册条目的HTML摘录(没有解释注释和说明格式的部分)可以在https://www.felixcloutier.com/x86/index.html和https://github.com/HJLebbink/asm-dude/wiki,以及其他各种地方有不同格式的旧版本。
正如@fuz所解释的,大多数组装商选择遵循此标准,但这不是必需的重要的部分是二进制兼容性,而不是asm源代码兼容性。
英特尔必须为指令指定名称,以便在其手册的其余部分中用英语谈论它们,而不是因为它们需要世界上每个人都使用相同的asm语法
我不确定英特尔的手册是否完全定义了一个完整的asm语法(例如,如何在寻址模式中指示段覆盖前缀)。
在某些情况下,它们远远超出了描述哪种机器代码的作用,例如,在字符串指令lods/stos/movs/cmps/scas(可能还有输入/输出)中,你会在英特尔的第2卷手册中找到这样的段落:
在汇编代码级别,允许使用两种形式的此指令:"显式操作数"形式和"无操作数"格式。显式操作数表(使用MOVS助记符指定)允许显式指定源操作数和目标操作数。这里,源操作数和目标操作数应该是分别指示源值和目标的大小和位置的符号。提供这种显式操作数形式是为了允许文档;但是,请注意,此表单提供的文档可能会产生误导。也就是说,源和目标操作数符号必须指定操作数(字节、字或双字)的正确类型(大小),但不必指定正确的位置。源操作数和目标操作数的位置始终由DS:(E)SI和ES:(E)DI寄存器指定,在执行移动字符串指令之前,必须正确加载这些寄存器。
(突出显示从(HTML摘录)原始PDF)
一些"英特尔语法";像NASM这样的汇编器忽略了这一点,只允许使用大小为助记符一部分的movs
,比如movsb
。NASM还具有指示段覆盖前缀(如fs lodsd
)的语法,该前缀不需要操作数,因此这完全避免了使用指示错误内存操作数但仍进行汇编的操作数的可能性。
(字符串指令只使用隐式内存操作数,而不是ModR/M寻址模式。)
NASM:解析器:预期指令rep-movs
转换汇编代码lods和stos中的指令,以便NASM可以编译
是的,英特尔语法汇编有多种风格,更不用说像AT&T.
AT&T有意为某些指令使用不同的助记符,甚至将英特尔语法中共享助记符的一些操作码拆分为单独的助记码,如movzb
表示带字节源的movzx
,movzw
表示单词源版本。(通常也与大小后缀一起使用,如movzbl
,但如果您愿意,可以从32位目标寄存器推断出l
。)
而AT&当与两个寄存器操作数一起使用时,T语法无意地将fsubr
与fsub
交换,这是我们遇到的语法设计错误。(幸运的是,x87作为一个整体基本上已经过时了。)