如果我们只对它的低 4 字节使用 mov 操作,64 位寄存器的高 4 字节是否设置为零

Are a 64-bit register's higher 4 bytes set to zero if we only use mov operation on its lower 4 bytes

我正在从计算机系统学习 x86-64 汇编:程序员的视角,我遇到了一个练习,该练习要求将一行 C 代码转换为(两个)等效的汇编指令。该代码是关于使用指针将一种类型的变量复制到另一种类型。

指针变量声明如下:

src_t *sp; //src_t and dest_t are typedefs
dest_t *dp;

待翻译的C代码为:

*dp = (dest_t)*sp;

假设指针spdp分别存储在寄存器%rdi%rsi中,我们应该设置'appropriate portion' %rax(例如 %eax%ax%al)进行中间数据复制(因为 x86-64 不允许源和目标都是内存引用) .

现在src_tunsigned chardest_tlong,我做了下面的汇编代码:

movzbq (%rdi), %rax //move a byte into %rax with zero extension
movq %rax, (%rsi) //move 8 bytes of 'long' data 

但是这本书以及 Godbolt(使用 gcc-O3)说它应该是

movzbl  (%rdi), %eax
movq    %rax, (%rsi)

在这种情况下,字节仅(?)零扩展为 4 个字节(%eax 是 4 个字节长),但我读到如果我们喜欢

movl %edx, %rax

那么%rax的高4字节也会被设置为0

我有两个问题:

  1. movl %edx, %rax是否等同于movl %edx, %eax,即后一种情况高4字节也设置为0?
  2. movzbq (%rdi), %rax 是否等同于 movzbl (%rdi), %eax,即 movzbl 是否也将高 4 字节设置为零(如 movl),即使我们 不要提到完整的寄存器 (%rax) 但只是它的一部分 (%eax)?

一般来说,在 x86_64,任何以 32 位通用寄存器为目标的指令(任何 %eXX 或 %rNd 寄存器)也会设置相应 64 位寄存器的高 32 位注册为 0。因此,每条具有 32 位目标的指令都将其扩展为 64 位。

来自英特尔 IA32 软件开发人员手册(第 3.4.1.1 节):

When in 64-bit mode, operand size determines the number of valid bits in the destination general-purpose register:

  • 64-bit operands generate a 64-bit result in the destination general-purpose register.
  • 32-bit operands generate a 32-bit result, zero-extended to a 64-bit result in the destination general-purpose register.
  • 8-bit and 16-bit operands generate an 8-bit or 16-bit result. The upper 56 bits or 48 bits (respectively) of the destination general-purpose register are not modified by the operation. If the result of an 8-bit or 16-bit operation is intended for 64-bit address calculation, explicitly sign-extend the register to the full 64-bits.