【发布时间】:2019-02-25 07:03:00
【问题描述】:
看了this stack overflow answer,和this document,还是不明白movq和movabsq的区别。
我目前的理解是,在movabsq 中,第一个操作数是 64 位立即操作数,而 movq 符号扩展了 32 位立即操作数。从上面引用的第二个文件:
可以使用
movq指令将立即数数据移动到 64 位寄存器,该指令将对 32 位立即数进行符号扩展,或者使用movabsq指令,当完整的 64 位立即数是必填。
在the first reference,彼得说:
有趣的实验:
movq $0xFFFFFFFF, %rax可能无法编码,因为它不能用符号扩展的 32 位立即数表示,并且需要 imm64 编码或%eax目标编码。(编者注:这个错误的假设已在该答案的当前版本中得到修复)。
但是,当我组装/运行它时,它似乎工作正常:
.section .rodata
str:
.string "0x%lx\n"
.text
.globl main
main:
pushq %rbp
movq %rsp, %rbp
movl $str, %edi
movq $0xFFFFFFFF, %rsi
xorl %eax, %eax
call printf
xorl %eax, %eax
popq %rbp
ret
$ clang file.s -o file && ./file
打印0xffffffff。 (这同样适用于较大的值,例如,如果您添加几个额外的“F”)。 movabsq 生成相同的输出。
Clang 是在推断我想要什么吗?如果是,movabsq 是否比movq 更有优势?
我错过了什么吗?
【问题讨论】:
-
如有疑问,请检查拆卸。我没有尝试过
clang,但gas默默地将其转换为movabsq。movabsq的重点是明确表示您想要 64 位立即数,例如即使文字适合 32 位或符号。 -
也许可以尝试使用
$label作为立即数,因此汇编器在汇编时不知道标签的绝对地址是否适合 32 位立即数。直到链接时间才知道。 -
我更新了我对另一个问题的回答,
mov $symbol, %rdi和movabs $symbol, %rdi等等。感谢您发现这个错误的假设。我什至测试了 2008 年的旧版本 GAS,它仍然使用 10 字节编码而不是截断,所以我的猜测可能永远不会对汇编时常量正确,只有链接时常量(地址)。
标签: assembly x86-64 att immediate-operand