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

tec*_*ury 1 c assembly gcc x86-64

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

指针变量声明如下:

src_t *sp; //src_t and dest_t are typedefs
dest_t *dp;
Run Code Online (Sandbox Code Playgroud)

需要翻译的C代码是:

*dp = (dest_t)*sp;
Run Code Online (Sandbox Code Playgroud)

假设指针sp和分别dp存储在寄存器%rdi%rsi中,并且我们应该设置%rax(例如 、%eax%ax)的“适当部分”%al来进行中间数据复制(因为 x86-64 不允许源和目标同时复制)是内存引用)。

现在,当src_tisunsigned chardest_tis 时long,我为其编写了以下汇编代码:

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

但这本书以及Godboltgcc (与 一起使用-O3)都说它应该是

movzbl  (%rdi), %eax
movq    %rax, (%rsi)
Run Code Online (Sandbox Code Playgroud)

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

movl %edx, %rax
Run Code Online (Sandbox Code Playgroud)

那么%rax的高4个字节也将被设置为0。

我有两个问题:

  1. 相当于movl %edx, %raxmovl %edx, %eax即后一种情况高4字节是否也设置为0?
  2. 相当于movzbq (%rdi), %raxmovzbl (%rdi), %eaxiemovzbl也将较高的 4 个字节设置为零(如movl),即使我们没有提到完整的寄存器%rax),而只提到其中的一部分%eax)?

Chr*_*odd 5

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

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

在 64 位模式下,操作数大小决定目标通用寄存器中的有效位数量:

  • 64 位操作数在目标通用寄存器中生成 64 位结果。
  • 32 位操作数生成 32 位结果,并在目标通用寄存器中零扩展为 64 位结果。
  • 8 位和 16 位操作数生成 8 位或 16 位结果。该操作不会修改目标通用寄存器的高 56 位或 48 位(分别)。如果 8 位或 16 位运算的结果用于 64 位地址计算,请显式将寄存器符号扩展为完整的 64 位。


归档时间:

查看次数:

2046 次

最近记录:

4 年,9 月 前