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



我刚刚尝试了这个问题,它要求您解释代码行的问题:

movl %eax, %rdx

解决方案表明目标操作数大小错误。

它只是";非法的";如果从较大的大小变为较小的大小,或者对于所有指令(或者至少mov类类型(,源操作数和目标操作数的大小必须相同?

是的,除了一些特殊指令(如shl %cl, %eaxmovzwl %ax, %edx(之外,操作数的大小必须相同。

CPU执行机器代码,而不是程序集。在机器代码中,有操作码和前缀(以及64位模式下提供的默认值(来指定操作数大小。不为每个操作数分离大小属性;那将是一种浪费。

汇编语言是一种用于描述/指定机器指令的文本格式。

ISA设计者(英特尔,然后是64位模式的AMD(选择用窄操作数大小来定义指令集中部分寄存器的语义。当您写入AL、AH或AX(由Intel在8086和808386中定义,AMD64与之匹配(时,对完整寄存器的影响是合并的,或者当您写入EAX时,隐式零扩展到RAX(AMD64中针对寄存器新部分的新语义(。

请参阅为什么32位寄存器上的x86-64指令会将整个64位寄存器的上部清零以及英特尔针对movmovsx(以及AMD64新增的movsxd(等指令的指令集参考。

在asm文本语法中,没有对应于movl %eax, %rdx的机器代码
汇编程序正确地告诉您这是没有意义的

这也是为什么AT&T语法将操作数大小后缀(b/w/l/q(附加到助记符,而不是分别附加到每个操作数。唯一的歧义是没有寄存器操作数的指令,只有立即数和内存,如andl $1, (%rdi)andb $1, (%rdi)notq (%rdi, %rsi, 8)

有一条指令movsld %eax, %rdx符号将从32位扩展到64位。(32到64没有movzx;这在mov %eax, %edx中是隐含的:MOVZX缺少32位寄存器到64位寄存器,只有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语法为CCD_ 27。

我认为,假设的设计不如说大多数指令要求所有操作数的宽度相同直观。在实践中,AT&设计了T语法。相反,AT&T遵循了与英特尔/AMD在其手册中使用的相同约定,只是操作数顺序颠倒了。我不知道任何以这种方式工作的ISA有任何语法;当写入一个窄寄存器时,隐式零扩展,这在asm文本语法中是隐式的(例如,在AArch64和所有各种x86-64语法中;Intel、AT&T、Plan9/Go(


参考文献:

  • x86-64(AMD64(体系结构中是否有默认操作数大小?-是的,在64位模式下,除了字节操作数大小的操作码外,大多数操作码都是32位的。16和64比特大小由前缀发信号通知。

  • 为什么在64模式下默认操作数大小为32位?-并且这种选择是有意义的,因为32位int足够大并且在其他历史原因中被普遍使用。

  • https://wiki.osdev.org/X86-64_Instruction_Encoding

  • 以及中的英特尔手册和其他链接https://stackoverflow.com/tags/x86/info

  • 为什么不';当操作数大小相同时,MOVZX是否工作?-它确实做到了,但效率低下,所以大多数组装商都拒绝它。

最新更新