是的,除了一些特殊指令(如shl %cl, %eax或movzwl %ax, %edx)外,操作数必须具有相同的大小。 CPU执行机器码,而不是汇编。在机器码中,有操作码和前缀(以及64位模式下提供的默认值)来指定操作数的大小。每个操作数没有单独的大小属性;那就太浪费比特了。 汇编语言是一种用于描述/指定机器指令的文本格式。 伊萨设计人员(Intel,然后是AMD的64位模式)选择根据窄操作数大小来定义指令集中部分寄存器的语义。(由英特尔在8086和808386中定义,AMD 64与之匹配),或者在编写EAX时隐式零扩展到RAX(AMD 64中新的寄存器部分的新语义)。 请参阅 * Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register? * 和英特尔的指令集参考,了解指令like mov与movsx(以及AMD 64中新增的movsxd)。
1条答案
按热度按时间jljoyd4f1#
是的,除了一些特殊指令(如
shl %cl, %eax
或movzwl %ax, %edx
)外,操作数必须具有相同的大小。CPU执行机器码,而不是汇编。在机器码中,有操作码和前缀(以及64位模式下提供的默认值)来指定操作数的大小。每个操作数没有单独的大小属性;那就太浪费比特了。
汇编语言是一种用于描述/指定机器指令的文本格式。
伊萨设计人员(Intel,然后是AMD的64位模式)选择根据窄操作数大小来定义指令集中部分寄存器的语义。(由英特尔在8086和808386中定义,AMD 64与之匹配),或者在编写EAX时隐式零扩展到RAX(AMD 64中新的寄存器部分的新语义)。
请参阅 * Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register? * 和英特尔的指令集参考,了解指令like
mov
与movsx
(以及AMD 64中新增的movsxd
)。**在asm文本语法中,没有与
movl %eax, %rdx
对应的机器码。汇编程序会正确地告诉您这是没有意义的。**
这也是AT&T语法在助记符后面加上操作数大小后缀(
b
/w
/l
/q
)的原因,而不是单独加到每个操作数上。唯一的歧义是没有寄存器操作数的指令,只有立即数和内存,比如andl $1, (%rdi)
和andb $1, (%rdi)
或notq (%rdi, %rsi, 8)
。有一个指令
movsld %eax, %rdx
tosign-extend从32位扩展到64位。(没有movzx
用于32位扩展到64位;这是mov %eax, %edx
中隐式表达式:* MOVZX missing 32 bit register to 64 bit register *,仅限8位或16位源操作数,如movzbl %al, %edx
。)还有其他具有不同大小的操作数的特殊指令,例如
shl %cl, %edx
这样的移位。这种语法设计适用于
mov %eax, (%rdi)
或add (%rdi), %esi
之类的加载/存储,其中寄存器操作数表示内存操作数大小。如果mov
可以有两个不同的大小,则始终需要指明内存操作数大小。就像你在movzx/movsx的助记符中所做的那样。(例如,AT&T语法movzbl (%rdi), %eax
通过显式地写EAX,隐式地将一个字节从内存零扩展到RAX。)描述机器代码的文本语法的其他设计 * 也是可能的*,例如,您可以发明一种语法,其中
movl %eax, %rdx
只是使零扩展显式化,并且可能不允许movl %eax, %edx
,因为如果不 * 隐式地将零扩展到64位,就无法写入32位寄存器。然后,您可以将movl (%rdi), %rdx
定义为32位负载(由l
后缀表示),并将其零扩展到64位RAX中,即我们目前在AT&T语法中定义的movl (%rdi), %edx
。我认为这种假设性的设计不如说大多数指令要求所有操作数的宽度都相同那么直观。实际上,这并不是AT&T语法的设计方式。相反,AT&T采用了英特尔/ AMD在其手册中使用的相同约定,只是操作数顺序颠倒了。我不知道任何伊萨的语法是这样工作的;当写入窄寄存器时,隐式地进行零扩展,这在asm文本语法中是隐式的(例如,在AArch 64和所有各种x86-64语法中;英特尔、AT&T、Plan 9/Go)
参考文献: