代码之家  ›  专栏  ›  技术社区  ›  Ashley Meah

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

  •  5
  • Ashley Meah  · 技术社区  · 10 年前

    举个例子,假设我正在构建一个虚拟机。我有一个字节数组和一个while循环,我如何知道要从字节数组中读取多少字节,以便下一条指令解释一个类似Intel8086的指令?

    编辑:(评论)

    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 回复  |  直到 5 年前
        1
  •  8
  •   old_timer    10 年前

    cpu简单地解码指令。在8086的情况下,第一个字节告诉处理器要获得多少。它不一定是第一个字节,第一个字节必须以某种方式表明你需要得到更多,更多可以表明你需要更多。对于像x86系列这样的8位指令集,您从一个字节开始,然后查看需要多少字节,并且还未对齐,因此必须将指令流视为字节流才能对其进行解码。

    你应该自己编写一个非常简单的指令集模拟器,只有少量的指令,也许足以加载一个寄存器,添加一些东西,然后循环。对于你想理解的东西来说,这是非常有教育意义的,如果要写的话,可能需要半个小时。

        2
  •  7
  •   phuclv    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字节。因此,如果你知道你是从一条指令开始的(并不总是一个安全的假设),那么字节是 第8页 ,您知道这是一条5字节的指令,下一条指令应该在5字节之后开始。

    请注意,这两个指令( mov eax, 0 xor eax, eax )有效地做同样的事情,将eax清除为0。

    例外情况:

    跳转/调用可能会变得棘手。可以跳转到 “指令中间” …但仍然执行。

    让我们看看:

    mov eax, 0x90909090
    

    机器代码:

    b8 90 90 90 90
    

    如果我们稍后有一条jmp指令跳转到上述指令的第三个字节的地址(在它中间的某个位置),它只会执行3个NOP(无操作),然后跳转到它后面的下一条指令(不将eax设置为0x909090)。这是因为 NOP 是由0x90组成的1字节指令。