assembly 源操作数和目标操作数的大小是否需要相同?

llew8vvj  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(247)

我刚刚试了一下这个问题,它要求你解释代码行的错误:

movl %eax, %rdx

解决方案指出目的操作数得大小错误.
是否只有从较大的大小变为较小的大小才是“非法的”,或者对于所有指令(或至少是mov类类型),源操作数和目标操作数的大小必须相同?

jljoyd4f

jljoyd4f1#

是的,除了一些特殊指令(如shl %cl, %eaxmovzwl %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 movmovsx(以及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)
参考文献:

相关问题