C++ x86体系结构中的指令解码

C++ x86体系结构中的指令解码,c++,c,assembly,x86,decode,C++,C,Assembly,X86,Decode,我正在为我的实验室做一个操作系统项目,在那里我必须使用指令指针和指令操作码。现在我只需要知道它是什么类型的指令。为此,我从指令指针指向的地址读取数据。这个数据的第一个字节给出了指令类型。例如,如果第一个字节是0xC6,则它是一条MOVB指令。现在有些情况下,指令指针的第一个字节是0x0F。根据文档0x0F,这意味着它是一条双字节指令。我的问题是这种类型的教学。我不知道如何找出双字节指令的指令类型 在此之后,我的第二个优先事项是找出指令的操作数。我不知道如何从代码中实现这一点。任何样本代码将不胜感

我正在为我的实验室做一个操作系统项目,在那里我必须使用指令指针和指令操作码。现在我只需要知道它是什么类型的指令。为此,我从指令指针指向的地址读取数据。这个数据的第一个字节给出了指令类型。例如,如果第一个字节是
0xC6
,则它是一条
MOVB
指令。现在有些情况下,指令指针的第一个字节是
0x0F
。根据文档
0x0F
,这意味着它是一条双字节指令。我的问题是这种类型的教学。我不知道如何找出双字节指令的指令类型

在此之后,我的第二个优先事项是找出指令的操作数。我不知道如何从代码中实现这一点。任何样本代码将不胜感激

第三,需要找出指令的大小。由于x86是可变长度的,我想知道每个指令的大小。首先,我计划使用一个查找表,在这里我将维护指令名及其大小。但后来我发现同一条指令可以有可变长度。例如,当我在
.o
文件上使用对象转储时,我发现两条指令
C6 00 62
,用于
MOVB$0x62,(%EAX)
&用于
MOVB$0x0,-0xD4(%EBP)
C6 85 2C FF FF FF FF 00
。请看,这两种指令类型相同(
C6
),但长度不同


所以我需要这些问题的答案。如果有人能给我一些解决方案,我将不胜感激。

基本上,您需要的是一组嵌套的case语句,实现一个有限状态机扫描程序,其中每个级别检查操作码的一些字节(通常从左到右),以确定它的功能

您的顶级case语句几乎是256个case,每个操作码字节对应一个case; 您会发现一些操作码(特别是所谓的“前缀”字节)导致顶层循环(拾取主操作码字节之前的多个前缀字节)。子案例将根据x86的操作码结构获取结构;您几乎肯定会得到一个MODRM和SIB寻址模式字节解码器/子例程

我已经做到了;这项工作因细节而烦人,但并不难。如果你小心的话,你可以用几百行代码得到一个非常好的解决方案。如果你坚持做整个指令集(向量寄存器和操作码,尤其是haswell等),你可能会得到更大的结果;英特尔一直在把指令塞进他们能找到的每一个黑暗角落

你真的需要一个操作码映射;我很确定英特尔手册中有一个。我发现这个链接非常有用:

编辑2015年9月:在这里,我提供了实现此功能的C代码:

另一种方法是使用众多解析器生成器框架之一(如无处不在的yacc)为程序集实际构建一个合适的解析器。与在大量情况下使用嵌套switch语句相比,这可能会导致更易于维护和模式可读的实现


还有一种中间方法,可以“手动”实现基于表的解析器。这里有一个例子:

kvm
有一个非常复杂的x86仿真器/解码器,可以被您的项目重用。

您所问的问题非常复杂,不容易用SO格式回答。您可以检查流行的开源反汇编程序是如何实现这一点的(
gdb
objdump
)。还有!请提供更多的上下文。为什么一个操作系统项目需要模拟x86 CPU?@SevaAlekseyev我的项目需要使一个进程能够回溯到其早期状态。我应该用mprotect()来做。其思想是保护每个页面不受写操作的影响。因此,当有写入操作时,我将捕获它。在handler函数中,我将保存旧数据,从指令中提取新数据,使页面不受保护,再次运行指令,然后使页面再次受到保护。由于在处理程序内部,我不知道操作将写入什么值,所以我所能做的就是找到IP,获取指令操作数并再次执行它。可能还有其他技术,如二进制插装。但是我一直在使用MpCuto(),没有足够的时间考虑新的解决方案。为什么不使用T标志和调试基础设施呢?这就是在x86上单步执行的方式。巨型开关语句是邪恶的,很少能被原谅。:)@user16653:有时候邪恶是正确的:)是的,实际上我试着建立一个查找表,但是我在两字节指令方面遇到了问题。我不知道它们是怎么工作的。例如,我在指令指针中得到值0x0000000F,我真的不知道它是什么意思。它不填充PC中的任何类别0x0f与指令解码无关。这意味着程序跳转到0x0F。通常,操作系统会使VM的第一页和最后一页完全非法,因为这会捕获汇编代码将小的正常量或负常量移动到PC中的许多愚蠢错误;用户程序只是犯了一个巨大的错误,你的操作系统应该干脆把它关闭。。。。EIP->0F 00。。0F是一个锁或REPNE前缀字节。整个事情看起来有点像“LOCK ADD modrm…”我没有解码modrm部分;你可以这样做。事实上有很多工具。但是他们的来源现在对我来说太大了。我只想了解我提出的三点。“从那里我相信我能做一个简单的。”azizulfahim,在你的问题中,CPU状态已经减少到一个指令指针。这首先是对问题的过度简化。x86指令解码器本质上是以二进制字符串作为输入的DFA。它的过渡选项卡