是的,除了一些特殊指令之外,操作数必须具有相同的大小,例如shl %cl, %eax
or movzwl %ax, %edx
.
CPU 执行机器代码,而不是汇编。在机器代码中,有操作码和前缀(以及 64 位模式提供的默认值)来指定操作数大小。每个操作数没有单独的大小属性;那会浪费比特。
汇编语言是一种用于描述/指定机器指令的文本格式。
ISA 设计者(Intel,然后是 64 位模式的 AMD)选择根据窄操作数大小来定义指令集中部分寄存器的语义。当您写入 AL、AH 或 AX(由 Intel 在 8086 和 808386 中定义,AMD64 与之匹配)时,对完整寄存器的影响将被合并,或者当您写入 EAX 时,隐式零扩展到 RAX(AMD64 中的新语义)寄存器中新的部分)。
See 为什么 32 位寄存器上的 x86-64 指令会将整个 64 位寄存器的上部清零? https://stackoverflow.com/questions/11177137/why-do-x86-64-instructions-on-32-bit-registers-zero-the-upper-part-of-the-full-6以及 Intel 的指令集参考指令like mov https://www.felixcloutier.com/x86/mov vs. movsx https://www.felixcloutier.com/x86/movsx:movsxd (and movsxd
这是 AMD64 的新功能)。
在 asm 文本语法中,没有对应于的机器代码movl %eax, %rdx
.
汇编器正确地告诉你这是没有意义的。
这也是 AT&T 语法附加操作数大小后缀 (b
/w
/l
/q
) 到助记符,而不是单独到每个操作数。唯一的歧义是没有寄存器操作数的指令,只有立即数和内存操作数andl $1, (%rdi)
vs. andb $1, (%rdi)
or notq (%rdi, %rsi, 8)
.
有一个说明movsld %eax, %rdx
to 符号扩展从 32 位到 64 位。 (没有movzx
32 至 64;这隐含在mov %eax, %edx
: MOVZX 缺少 32 位寄存器到 64 位寄存器 https://stackoverflow.com/questions/51387571/movzx-missing-32-bit-register-to-64-bit-register,只有 8 位或 16 位源操作数,例如movzbl %al, %edx
.)
还有其他具有不同大小操作数的特殊指令,例如移位shl %cl, %edx
.
这种语法设计非常适合加载/存储,例如mov %eax, (%rdi)
or add (%rdi), %esi
,其中寄存器操作数意味着内存操作数大小。如果mov
可能有两个单独的大小,您总是需要指示内存操作数大小,就像您作为 movzx/movsx 助记符的一部分所做的那样。 (例如 AT&T 语法movzbl (%rdi), %eax
通过显式写入 EAX 将字节从内存隐式零扩展到 RAX。)
描述机器代码的文本语法的其他设计是possible,例如你可以发明一种语法,其中movl %eax, %rdx
只是使零扩展变得明确,也许movl %eax, %edx
不允许,因为无法写入 32 位寄存器without隐式零扩展至 64 位。然后你可以定义movl (%rdi), %rdx
作为 32 位负载(由l
后缀)零扩展到 64 位 RAX。即我们当前在 AT&T 语法中定义为movl (%rdi), %edx
.
我认为假设的设计比仅仅说大多数指令要求所有操作数具有相同的宽度更不直观。实际上,AT&T 语法并不是这样设计的。相反,AT&T 采用了与 Intel / AMD 在其手册中使用的相同约定,只是操作数顺序相反。我不知道任何以这种方式工作的 ISA 的语法;当写入窄寄存器隐式零扩展时,这会隐含在 asm 文本语法中(例如,在 AArch64 中,以及所有各种 x86-64 语法;Intel、AT&T、Plan9/Go)
参考:
-
x86-64 (AMD64) 架构中是否有默认操作数大小? https://stackoverflow.com/questions/68289333/is-there-a-default-operand-size-in-the-x86-64-amd64-architecture- 是的,在 64 位模式下,大多数操作码都是 32 位的,字节操作数大小的操作码除外。 16 和 64 位大小由前缀表示。
-
为什么 64 模式下默认操作数大小为 32 位? https://stackoverflow.com/questions/59849429/why-is-default-operand-size-32-bits-in-64-mode- 这个选择是有道理的,因为 32 位int
除其他历史原因外,它足够大且常用。
-
https://wiki.osdev.org/X86-64_Instruction_Encoding https://wiki.osdev.org/X86-64_Instruction_Encoding
-
以及英特尔的手册和其他链接https://stackoverflow.com/tags/x86/info https://stackoverflow.com/tags/x86/info
-
为什么当操作数大小相同时 MOVZX 不起作用? https://stackoverflow.com/questions/67933514/why-doesnt-movzx-work-when-operands-have-the-same-size- 它确实如此,但效率低下,因此大多数汇编器拒绝它。