【问题标题】:Assembly - Mov instruction and operands size汇编 - 移动指令和操作数大小
【发布时间】:2019-04-04 11:30:47
【问题描述】:

当我们在汇编中使用 mov 指令时,源操作数和目标操作数必须具有相同的大小。 如果我写:

mov rax, 1

是否根据 rax 寄存器的大小转换了 1 操作数?

例如,如果 rax 是 16 位,我们得到:

0000000000000001

?

【问题讨论】:

  • RAX 是 64 位的。在 64 位模式下,一般来说,立即数是 32 位(符号或零扩展)或 64 位。
  • @MargaretBloom:对于使用窄立即数的操作码,立即数总是符号扩展为操作数大小。至少我想不出它们在哪里是零扩展的。如果你想要零扩展,你必须使用mov eax, imm32,它具有 32 位操作数大小并遵循写一个 32 位寄存器零扩展以填充 64 位寄存器的通常规则。 Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?。 (我假设这就是你的意思,但如果我们考虑更窄的操作数大小,那么 16 位和 8 位是
  • 有特定指令 movabs rax,<64b immediate> 将包含编码值“1”作为 64b 整数,但常见的现代汇编器 NASM 将例如 mov rax,1 汇编成指令 mov eax,1 与 32b 立即数(机器代码b8 01 00 00 00),它将以完全相同的方式设置最终的rax 内容,但编码要短得多。 .. 无论如何,如果指令将rax 作为目标寄存器,那么您可以打赌,无论进行什么操作,都会以整个 64 位目标寄存器为目标。如何/是否扩展操作数取决于特定的指令和操作数。
  • @PeterCordes FASM 似乎可以做到,让我看看能不能拿到一份 MASM。
  • 不,抱歉@Peter,FASM 不这样做,但 MASM 可以。

标签: assembly x86-64


【解决方案1】:

有 2 种语言。第一个是汇编语言,你可能有一个字符串,比如“mov rax,1”。第二种是机器语言,您将拥有一组字节。

这些语言是相关的,但又不同。例如,汇编语言中的mov指令实际上是机器语言中的多个不同操作码(一个用于将字节移入/移出通用寄存器,一个用于将words/dwords/qwords移动到通用寄存器,一个用于移动dwords/qwords控制寄存器,一个用于将 dwords/qwords 移动到调试寄存器等)。汇编器使用指令及其操作数来选择适当的操作码(例如,如果您执行mov dr6,eax,那么汇编器将选择用于将 dwords/qwords 移动到调试寄存器的操作码,因为其他操作码都不适合)。

同理,操作数可能不同。例如,对于汇编语言,常量1 具有“整数”类型并且没有任何大小(其大小隐含在其使用方式/使用位置);但在机器代码中,必须以某种方式对立即操作数进行编码,并且编码的大小将取决于 mov 使用的操作码(和前缀)。

例如,如果mov rax,1转换成字节0x48、0xC7、0xC0、0x01、0x00、0x00、0x00;那么您可以说操作数是“以 4 个字节编码的 64 位(使用符号扩展)”;或者您可以说操作数是以 4 个字节编码的 32 位(并且该指令仅将 32 位移动到 RAX 中,然后符号扩展到 RAX 的高 32 位,而不是将任何内容移动到其中)。尽管这些事情听起来不同(尽管大多数人会说后者“更正确”),但行为完全相同,唯一的区别是机器代码的表面差异(一种不是汇编语言的不同语言)被描述。在汇编语言中,1 仍然是一个(“从上下文中暗示”)64 位操作数,无论在机器语言中发生什么。

【讨论】:

  • 有两个操作码用于将字节移入/移出 GP 寄存器(每个方向一个)。如果包含mov reg, imm,则为第三个:移动立即字节。实际上是两倍,因为 8 位操作数大小与 16/32/64 不同的操作码(具有不同前缀的相同操作码)。但无论如何,“用于 mov 到/从 GP regs 的一个操作码”绝对不是字面上正确的。一个指向felixcloutier.com/x86/MOV.html 的链接在这里是个好主意。
  • 您的最后一段看起来像是在描述b8 01 00 00 00 (mov eax,imm32) 编码。您展示的 7 字节编码使用符号扩展的 32 位立即数,并且确实使用 64 位操作数大小写入完整的 RAX,而不是将它们留给隐式零扩展。一旦你修复了这个错误,我很乐意为这个答案 +1,我认为你已经准确地确定了 OP 在 asm 和机器代码之间的混淆。
  • @PeterCordes:您可以将其描述为 2 个不同的 8 位操作码,或者您可以将其描述为一个 7 位操作码,其中包含一个额外的“方向”参数插入(最低)位,或者您可以将其描述为 32 个不同的 16 位操作码(每个寄存器一个,每个方向一个),或者......不管有人如何描述它都是一样的。
  • 这很公平;英特尔按照我描述的方式定义它,但你看待它的方式也是有道理的。我假设您正在更新其他要点,尤其是最后一段。
  • @PeterCordes:对于我在示例中使用的编码,我只是将“mov rax,1”放入在线汇编程序(defuse.ca/online-x86-assembler.htm)并复制它所说的内容。汇编器可以选择不同的方式来编码相同的指令,并且在示例中使用哪种方式并不重要。请注意,这实际上可以有实际用途 - 例如我知道至少有一个汇编器(a86 和 a386)将其用于反盗版(因此汇编器的作者可以根据选择的编码判断他们的汇编器是否被使用)。
猜你喜欢
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 2016-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多