0

我正在创建一个 x86 解码器,我正在努力理解和寻找一种有效的方法来计算指令的助记符。

我知道操作码 6 MSB 是操作码位,但我在助记符表中找不到使用这 6 位的任何地方。我找到的唯一助记表是针对整个操作码字节本身,而不仅仅是 6 个 MSB。

我想问有哪些有效的方法可以继续解码操作码字节中编码的助记符,以及是否有任何使用 6 个 MSB 而不是整个操作码字节的表引用。

4

1 回答 1

1

但是没有一种有效的方法来存储一个没有重复的助记符表吗?

这已成为算法和数据结构的问题。

正如您所指出的,许多操作码表条目(至少对于没有0f转义字节的表: http: //sparksandflames.com/files/x86InstructionChart.html)确实以 4 或 2 组重复,即相同的 6或选择相同助记符的 7 位前缀。

显然,一个 256 条目的结构表很简单,但重复了一些东西。它非常快速且易于使用,因为它可能仍然足够小,不会经常缓存丢失。(特别是因为公共条目将在缓存中保持热;x86 代码大量使用相同的操作码。)

您可以用简单/性能换取空间。

您可以有一个 64 条目的结构表,其中一个成员是指向要使用低 2 位索引的辅助表的指针。如果指针为 NULL,则表示指令遵循add/ and/ xor/ 等模式,其中低 2 位告诉您 8 位与无论操作数大小和方向如何(r/m,reg 或 reg,r/m )。

rep nop当存在某些前缀(例如is pause)时,您的结构还需要用于转换为其他指令的条目。此外,AVX VEX 前缀使用了过去对另一条指令无效的编码。如果你想为所有当前的扩展做一个完整的工作,x86 解码是相当疯狂的。

实际上,只使用函数指针表可能是最简单的(也是有效的) 。或者一个带有 aconst char* mnemonic和一个int (*decode)(const char*mnemonic, const char *insn_bytes, unsigned prefix_bitmap)函数的结构,所以很多操作码可以指向同一个解码函数,但仍然得到不同的助记符。有时该函数会忽略传递的助记符,但有时这就是它所需要的全部。您将拥有一个用于解码许多解码函数会调用的寻址模式的通用函数。

这与您实现解释的 x86 仿真器的方式非常相似,而不是进行动态重新编译。一个常见的解码循环,然后通过函数指针进行调度。


您可能使用的更复杂的数据结构是radix trie又名前缀树。另请参阅https://en.wikipedia.org/wiki/Trie#Bitwise_tries

这是进入愚蠢的季节,因为密度如此之高以至于查找表更有意义。(很少有未定义的操作码)。

于 2017-09-15T10:00:08.130 回答