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

Moving a value of a lesser size into a register

我已经存储了 8 的一个字节值,我想将其移入 rax 寄存器。我目前正在使用 movzx 对字节进行零扩展:

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

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

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

mov [=11=], %rax
mov -1(%rbp), %al

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

How does the movzx instruction 'know' that the value at -1(%rbp) is only one byte long?

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

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

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

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

它有歧义并且依赖于一些默认值,你不应该这样写代码。

这就是为什么 AT&T 语法有 movzbmovzw 指令(通常用作 movzbl -1(%rbp), %eax),用于 Intel-syntax [=16= 的两种不同的源大小】 助记。参见 (不,AT&T 编造了新名称。)

是的,您 可以 xor %eax,%eax / mov -1(%rbp), %al 合并到低字节,但那毫无意义地低效。 x86-64保证像movzx.

这样的386指令的可用性

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

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

或将 assemble 转换为英特尔语法 objdump -drwC -Mintel:

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

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

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

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

也相关:cdq 的 table 等 movsx 和 AT&T 等价物:What does cltq do in assembly?

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