将较小大小的值移动到寄存器中

Posted

技术标签:

【中文标题】将较小大小的值移动到寄存器中【英文标题】:Moving a value of a lesser size into a register 【发布时间】:2020-08-13 06:10:48 【问题描述】:

我存储了一个单字节值8,我想将它移到rax 寄存器中。我目前正在使用movzx 对字节进行零扩展:

.globl main
main:
    push %rbp
    mov %rsp, %rbp
    movb $8, -1(%rbp)
    movzx -1(%rbp), %rax <-- here
    ...

movzx 指令如何“知道”-1(%rbp) 处的值只有一个字节长?从这里说,如果我正确阅读它,它可以在byteword 上工作,但它怎么知道呢?例如,如果我在-2(%rbp) 处添加了一个两字节值,它如何知道获取该两字节值?是否有另一条指令可以让我在某个地址处获取 onetwofour 字节值并将其插入 64 位寄存器?

我想另一种方法是先将寄存器清零,然后将其添加到 8 位(或许多位)组件中,例如:

mov $0, %rax
mov -1(%rbp), %al

有没有一种方式比另一种方式更受欢迎?

【问题讨论】:

【参考方案1】:

它是模棱两可的并且依赖于一些默认值,你不应该写这样的代码。

这就是 AT&T 语法具有 movzbmovzw 指令(通常用作 movzbl -1(%rbp), %eax)的原因,用于 Intel 语法 movzx 助记符的两种不同源大小。请参阅Are x86 Assembly Mnemonic standarized?(不,AT&T 编造了新名称。)

是的,您可以 xor %eax,%eax / mov -1(%rbp), %al 合并到低字节中,但这毫无意义的低效。 x86-64 保证 movzx 等 386 条指令的可用性。

令人惊讶的是,movzx -1(%rbp), %rax 确实组装了。如果你组装它,然后用 objdump -d foo.o 反汇编回 AT&T 语法,你会得到 movzbq(字节到四边形),包括一个无用的 REX 前缀,而不是在编写 EAX 后让 implicit zero-extension do the job。

48 0f b6 45 ff          movzbq -0x1(%rbp),%rax

或者用objdump -drwC -Mintel反汇编成Intel语法:

48 0f b6 45 ff          movzx  rax,BYTE PTR [rbp-0x1]

有趣的事实:如果你只写movz,GAS 无法推断出movzbmovzw,因为movz 不是指令助记符。与可以从操作数推断出的操作数大小后缀不同,bw 被视为助记符的一部分。但是你可以写movzx,然后它会从寄存器操作数中推断出两种大小,就像在 Intel 语法模式中一样。

   5:   0f b6 c0                movzbl %al,%eax         # source: movzx %al, %eax
   8:   0f b7 c0                movzwl %ax,%eax         # source: movzx %ax, %eax

movzwmovzb 本身就像指令助记符(可以从目标寄存器推断大小后缀)。半相关:What does the MOVZBL instruction do in IA-32 AT&T syntax?

还相关:一张 cdq 等等价物表,以 movsx 和 AT&T 等价物:What does cltq do in assembly?

也相关:MOVZX missing 32 bit register to 64 bit register - 因为这隐含在写入 32 位寄存器中。

【讨论】:

【参考方案2】:

movzx 指令如何“知道”-1(%rbp) 处的值只有一个字节长?

有两个(甚至三个)指令:

movzxb-1(%rbp) 是一个字节长)和movzxw-1(%rbp) 是一个 16 位字长)。

我的汇编程序将movzx 解释为movzxb;但是,您不应该依赖它!

最好使用包含源大小的指令名称(movzxbmovzxw),以确保汇编器使用正确的指令。

【讨论】:

太好了,感谢您的澄清。是否有第三条 32 位长的指令? @samuelbrody1249 对于movsx 指令,movsxl 使用 32 位源。 movzxl 似乎不存在,因为任何写入%eax 寄存器的操作都会隐式地将%rax 的高32 位设置为零。所以你可以简单地做一个mov -1(%rbp), %eax 指令。 movzxb 是 Intel 和 AT&T 语法的突变混合体。我不会推荐它,编译器从不使用它,我也从未在任何地方看到过它。不过,它显然与标准 AT&T movzb 等效。我很惊讶,我希望它是 movzx 的目标大小覆盖并且失败了。 (可能我完全弄错了,这在某处被记录或标准化,但我从未见过。) 请注意,这些的标准 AT&T 助记符是 movzblmovzwl。从 X 尺寸到 Y 尺寸的零扩展移动始终为 movzXY,符号扩展移动始终为 movsXY

以上是关于将较小大小的值移动到寄存器中的主要内容,如果未能解决你的问题,请参考以下文章

大小端模式,内存地址高低位,寄存器高低位

如何以编程方式确定如何将较小的盒子装入较大的包装中? [关闭]

HBase 链 MapReduce 作业,将较小的表广播到所有 Mapper

ARM汇编中LDR伪指令和LDR指令

按寄存器中的值移位位

linux入门汇编