将较小大小的值移动到寄存器中
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)
处的值只有一个字节长?从这里说,如果我正确阅读它,它可以在byte
和word
上工作,但它怎么知道呢?例如,如果我在-2(%rbp)
处添加了一个两字节值,它如何知道获取该两字节值?是否有另一条指令可以让我在某个地址处获取 one
或 two
或 four
字节值并将其插入 64 位寄存器?
我想另一种方法是先将寄存器清零,然后将其添加到 8 位(或许多位)组件中,例如:
mov $0, %rax
mov -1(%rbp), %al
有没有一种方式比另一种方式更受欢迎?
【问题讨论】:
【参考方案1】:它是模棱两可的并且依赖于一些默认值,你不应该写这样的代码。
这就是 AT&T 语法具有 movzb
和 movzw
指令(通常用作 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 无法推断出movzb
与movzw
,因为movz
不是指令助记符。与可以从操作数推断出的操作数大小后缀不同,b
和 w
被视为助记符的一部分。但是你可以写movzx
,然后它会从寄存器操作数中推断出两种大小,就像在 Intel 语法模式中一样。
5: 0f b6 c0 movzbl %al,%eax # source: movzx %al, %eax
8: 0f b7 c0 movzwl %ax,%eax # source: movzx %ax, %eax
movzw
和movzb
本身就像指令助记符(可以从目标寄存器推断大小后缀)。半相关: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
;但是,您不应该依赖它!
最好使用包含源大小的指令名称(movzxb
或movzxw
),以确保汇编器使用正确的指令。
【讨论】:
太好了,感谢您的澄清。是否有第三条 32 位长的指令? @samuelbrody1249 对于movsx
指令,movsxl
使用 32 位源。 movzxl
似乎不存在,因为任何写入%eax
寄存器的操作都会隐式地将%rax
的高32 位设置为零。所以你可以简单地做一个mov -1(%rbp), %eax
指令。
movzxb
是 Intel 和 AT&T 语法的突变混合体。我不会推荐它,编译器从不使用它,我也从未在任何地方看到过它。不过,它显然与标准 AT&T movzb
等效。我很惊讶,我希望它是 movzx
的目标大小覆盖并且失败了。 (可能我完全弄错了,这在某处被记录或标准化,但我从未见过。)
请注意,这些的标准 AT&T 助记符是 movzbl
和 movzwl
。从 X 尺寸到 Y 尺寸的零扩展移动始终为 movzXY
,符号扩展移动始终为 movsXY
。以上是关于将较小大小的值移动到寄存器中的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式确定如何将较小的盒子装入较大的包装中? [关闭]