【问题标题】:can we move content from smaller register to larger register我们可以将内容从较小的寄存器移动到较大的寄存器吗
【发布时间】:2020-07-08 00:32:02
【问题描述】:

例如,我们可以这样做:

movl %eax,%rdx    // l means 32 bits while rdx is 64 biregister

所以如果我们将%eax 的32 位内容移动到%rdx,那么只有%rdx 的低32 位会被更新?

【问题讨论】:

标签: assembly x86-64 instructions instruction-set


【解决方案1】:

没有直接的方法只写入 64 位 GPR 的低 32 位,但可以通过清除低 32 位并将值按位或运算来模拟:

shr rdx, 32
shl rdx, 32
or rdx, rax  ; assumes top 32 bits of rax are zero

或者使用双精度移位和旋转:

shrd rdx, rax, 32
ror rdx, 32

不幸的是,在大多数处理器上,这比第一个版本具有更高的延迟(可能 Core2 及其直接祖先除外),因为 (这种形式的)双精度移位通常需要 3 个周期。对于典型的 Intel 处理器,它在某些情况下具有潜在的优势,因为它总体上需要更少的 µops,但在 AMD Zen 和 Intel Atom 上,shrd 需要少量的 µops。所以一般来说第一个版本应该是首选,但在特定情况下可能有理由使用第二个版本。

两个重叠的存储和一个加载也是可能的(这很慢,例如,由于存储转发失败,Haswell 上的 16 个周期,即使没有遇到如此糟糕的微架构边缘情况,它也不会超过仅寄存器解决方案):

mov [rsp], rdx
mov [rsp], eax
mov rdx, [rsp]

【讨论】:

    【解决方案2】:

    movl %eax,%rdx(相当于mov %eax,%rdx)不是有效指令。 MOV 的有效组合可以在Instruction Set Architecture reference 中找到。

    有一些指令可以从较小的寄存器移动到较大的寄存器。您可以使用MOVZX 进行零扩展(高位设置为0),或MOVSX 符号扩展,其中源寄存器的最高位被复制到目标寄存器的所有高位中。在 64 位长模式下,如果任何指令(包括 MOV)的目标是 32 位寄存器,则处理器会自动将相应 64 位寄存器的高 32 位设置为 0。

    这些示例代表了从较小寄存器到较大寄存器的有效移动:

    movzx %al, %dx     # move 8-bit register to 16-bit register. Upper 8 bits of DX set to 0
    movzx %al, %edx    # move 8-bit register to 32-bit register. Upper 24 bits of EDX set to 0
                       #     Upper 32 bits of RDX also set to zero because EDX is 32-bit dest
    movzx %al, %rdx    # move 8-bit register to 64-bit register. Upper 56 bits of RDX set to 0
    
    movzx %ax, %edx    # move 16-bit register to 32-bit register.Upper 16 bits of EDX set to 0
                       #     Upper 32 bits of RDX also set to zero because EDX is 32-bit dest
    
    #movzx %eax, %rdx  # This instruction doesn't exist. Use mov %eax, %edx
    
    movsx %al, %dx     # Sign extend 8-bit register to 16-bit register
    movsx %al, %edx    # Sign extend 8-bit register to 32-bit register
                       #     Upper 32 bits of RDX set to ZERO because EDX is 32-bit dest
    movsx %al, %rdx    # Sign extend 8-bit register to 64-bit register
    
    movsx %ax, %edx    # Sign extend 16-bit register to 32-bit register
                       #     Upper 32 bits of RDX set to ZERO because EDX is 32-bit dest
    movsx %ax, %rdx    # Sign extend 16-bit register to 64-bit register
    
    movsx %eax, %rdx   # Sign extend 32-bit register to 64-bit register
    

    【讨论】:

    • 虽然这都是真实的信息,但它并没有真正解释如何做 OP 想要做的事情。 OP 希望将 eax 移动到 rdx 的下半部分,同时保留 rdx 的上半部分,而这些都没有。
    • @JosephSible-ReinstateMonica :除非我遗漏了什么,否则我在问题中看不到任何表明他希望保留高 32 位信息的内容。首先,标题中的问题是关于将较小的寄存器移至较大的寄存器。在这个问题中,他确实提出了另一个问题then only the low order 32 bits of %rdx get updated? 答案是否定的,因为他使用的指令甚至无效。我在回答中提到了这两个问题。
    • 那个“进一步的问题”就是我的意思。虽然他的示例指令无效,而且看起来答案是“单条指令不可能”,但在答案中说,并显示多条指令的解决方案不是更好吗?
    • @JosephSible-ReinstateMonica 不清楚他是否打算这样做!他从来没有问过您是否可以将较小的寄存器存储到较大的寄存器中并将值保留在上部。我的回答(在说明表中)指出mov %eax, %rdx 无效,但为了做我相信他要求的事情,我建议mov %eax, %edx 就足够了。我的回答基于这样一个前提,即由于他从未说过任何关于保留更高位的事情,所以这不是问题。如果 OP 要求保留较高位的情况,那么他可以接受另一个答案。
    • 我同意,我在 OP 的含义上掷骰子,但我很容易猜错了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多