2016-10-29 289 views
6

我是一个新手,刚开始学习汇编语言。所以请纠正我,如果我错了,或者如果这篇文章没有任何意义,我会删除。x86-64中movq和movabsq的区别

我说的是在X86-64英特尔架构的数据移动指令。我已经知道常规的movq指令只能有立即源操作数,可以用32位二进制补码表示,而movabsq指令可以有一个任意的64位立即数作为其源操作数,并且只能有一个寄存器作为目的地。

请您详细说明一下吗?这是否意味着我只能使用movabsq指令移动64位立即数?只有从立即价值到注册?我看不出我能如何将64位立即数值移到内存中。或者我在这里弄错了一些重要的东西。

+2

你必须将它移动到一个寄存器然后移动到内存。这里的所有都是它的。 –

回答

11

在NASM/Intel语法中,mov r64, 0x...根据常量选择a MOV encoding。有四种可选择的立即操作数:

  • 5字节mov r32, imm32。 (zero-extended to fill the 64-bit register like always)。 AT & T:mov/movl
  • 6字节mov r/m32, imm32。仅对内存目标有用。 AT & T: mov/movl
  • 7字节mov r/m64, sign-extended-imm32可以将8个字节存储到内存,或将64位寄存器设置为负值。 AT & T:mov/movq
  • 10字节mov r64, imm64。 (这是REX.W = 1版本相同的操作码作为mov r32, imm32的)AT & T:movabs

(字节计数仅用于寄存器的目的地,或寻址不需要一个SIB字节或DISP8模式/ disp32对比:只是操作码+ MODR/M + IMM32)


在气体与AT & T语法

movabsq意味着机器代码编码将包含一个64位值:或者是一个立即数,或者是一个绝对内存地址。没有movabsq,它不能。

使用AT & T语法在此what's new in x86-64 guide中提到了其中的一些。除非你想要一个更长的指令用于对齐的目的(而不是稍后用NOP填充),否则不要使用mov $1, %rax。使用mov $1, %eax获取5字节的格式。

有趣的实验:movq $0xFFFFFFFF, %rax可能不是encodeable,因为它不是一个符号扩展 32位立即所能表述的,并且需要无论是imm64编码或%eax目的地编码。

movabs与直接来源永远是imm64形式。 (movabs也可以是以64位绝对地址和RAX作为源或目标的MOV编码:如REX.W + A3MOV moffs64, RAX)。


一些Intel的语法汇编器(但不是GAS)将优化的32位常数到5字节mov r32, imm32(NASM做到这一点),而其他(如YASM)将使用7字节mov r/m64, sign-extended-imm32。他们都选择imm64编码只用于大常量,而不必使用特殊的助记符。


我不知道怎样才能在64位立即值转移到内存中。

这是一个单独的问题,答案是:你不能。 insn ref manual entry for MOV说明了这一点:具有imm64立即数操作数的唯一形式只有一个寄存器目的地,而不是r/m64。

如果您的值适合符号扩展的32位立即数,则movq $0x123456, 32(%rdi)将执行一个8字节的存储至存储器。限制是它只是一个imm32。

+0

[从64位地址加载到rax以外的其他寄存器](http://stackoverflow.com/q/19415184/995714) –

+0

为什么'movq $ 0xFFFFFFFF,%rax'不可编​​码?为什么5字节版本不工作? –

+0

@LưuVĩnhPhúc:因为您使用了'movq'。为了让gas使用5字节的无REX前缀编码,你必须自己进行优化并写入'movl $ 0xFFFFFFFF,%eax'。所以它就像YASM一样,不会为你优化它。 –