CPU /汇编器如何知道下一条指令的大小?

时间:2014-08-03 05:39:43

标签: assembly controls cpu instruction-set

为了举例,想象一下我正在构建一个虚拟机。我有一个字节数组和一个while循环,我如何知道从字节数组中读取多少字节,以便下一条指令解释类似于intel 8086的指令呢?

编辑:(评论) cpu在指令指针处读取操作码,8086和CISC有一个字节和两个字节指令。我怎么知道下一条指令是F还是FF?

编辑: 在http://www.swansontec.com/sintel.html

的这篇文章中找到了一个自己的答案
  

操作代码或操作码位于任何可选前缀之后。该   操作码告诉处理器执行哪条指令。此外,   操作码包含描述操作数大小和类型的位字段   期望。例如,NOT指令具有操作码1111011w。在   这个操作码,w位决定操作数是一个字节还是一个   字。 OR指令的操作码为000010dw。在这个操作码中,   d位确定哪些操作数是源和目标,以及   w位再次确定大小。一些说明有几个   不同的操作码。例如,当OR与累加器一起使用时   寄存器(AX或EAX)和常量,它具有特殊的节省空间   操作码0000110w,无需单独的ModR / M字节。   从大小编码的角度来看,记忆精确的操作码位不是   必要。大致了解可用的操作码类型   对于特定的指令更重要。

2 个答案:

答案 0 :(得分:6)

TLDR:

解决方案比固定大小的阵列更复杂。


这完全取决于上下文,这就是像IDA这样的反汇编程序有这么复杂的算法的原因。

指令是x86的可变长度。但是如果你知道指令的开始,你就会知道指令的结束位置。因此,您可能知道下一个开始的位置。我会尽快解释这些例外情况。但首先,这是一个例子:

ASM:
mov eax, 0
xor eax, eax

Machine:
b8 00 00 00 00
31 c0

说明:

移动到eax是B8,然后是32位(4字节)值以进入eax(因为eax是32位)。换句话说,mov eax, immediate将始终为5个字节。所以,如果你知道你正在开始一条指令(并不总是一个安全的假设),并且字节是B8,你知道它是一个5字节的指令,并且下一条指令应该在5字节之后开始。

请注意,两个指令(mov eax, 0xor eax, eax)都有效地执行相同操作,将eax清除为0。

例外:

跳跃/通话可能会变得棘手。可以跳转到"指令中间的地址空间" ...但仍然可以执行。

让我们看看:

mov eax, 0x90909090

机器代码:

b8 90 90 90 90

如果我们后来有一个jmp指令跳转到上面指令的第3个字节的地址(在某个地方的中间),它只会做3个NOP(无操作)并落到下一条指令之后(不将eax设置为0x90909090)。这是因为NOP是由0x90组成的1字节指令。

答案 1 :(得分:6)

cpu只是对指令进行解码。在8086的情况下,第一个字节告诉处理器要获得多少。它不必是第一个字节必须以某种方式指示您需要获得更多的第一个字节,更多可以表明您需要更多。使用像x86系列这样的8位指令集,从一个字节开始,然后看看你需要多少,还有未对齐,你必须将指令流视为字节流,以便对其进行解码。

你应该为自己编写一个非常简单的指令集模拟器,只需要少量指令,可能足以加载寄存器,向其中添加内容然后循环。对于你想要了解的内容极具教育意义,如果要写,可能需要半个小时。