しかし、ニーモニックのテーブルを重複なく保存する効率的な方法はありませんか?
これはアルゴリズムとデータ構造の問題になっています。
opcodeテーブルエントリの多く(少なくとも0f
エスケープバイトのないテーブルの場合:http://sparksandflames.com/files/x86InstructionChart.html)は、4または2のグループで繰り返されます。つまり、同じ6または7ビット接頭辞が同じニーモニック。
明らかに、256エントリの構造体テーブルはシンプルですが、重複しています。非常に速く、使いやすいです。なぜなら、キャッシュミスが頻繁に起こらないほど小さいためです。 (特に、共通エントリはキャッシュ内で暑くなるため、x86コードでは同じオペコードが多く使用されます)。
スペースのシンプルさとパフォーマンスを交換できます。
構造体の64エントリテーブルを持つことができます.1つのメンバは、下位2ビットのでインデックスを付けるセカンダリテーブルへのポインタです。ポインタがNULLの場合は、命令がadd
/and
/xor
などのパターンに従うことを意味します。下位2ビットは、オペランドサイズと方向(r/m、reg、reg、 r/m)。
構造体には、特定の接頭辞がある場合に別の指示に進むためのエントリも必要です(rep nop
はpause
)。また、AVX VEXプレフィックスは、他の命令の無効な符号化であったものを使用します。 x86は、現在のすべての拡張機能の完全な仕事をしたいのであれば、デコードするのは非常に夢中です。
実際には、には、関数ポインタのテーブルを使用するのが最も簡単で(効率的かもしれません)。またはconst 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も参照してください。
密度が非常に高く、ルックアップテーブルがはるかに理にかなっているため、これは愚かなシーズンになりつつあります。(未定義のオペコードはほとんどありません)。
下位2ビットもopcodeの一部です...たとえば、['jcc'](http://felixcloutier.com/x86/Jcc.html)の命令では、opcodeの値が0x70から0x70になるごとに異なるニーモニックがあります。 0x7F。実際には、ModR/Mバイトからの '/ r'フィールドがオペコードの一部であることもあります。 (例えば 'shl'対' shr')。 –
最新のx86マシンコードの問題点は、効率的で簡単な方法ではないことです。たとえば 'rep nop'は実際には' pause'としてデコードされ、 'rep bsf'は' tzcnt'としてデコードされます(BMI1がサポートされていれば 'bsf'としてデコードされます)。したがって、他の指示の必須プレフィックスを確認する必要があります。 –
@PeterCordes私が使用していたリソースの1つはhttp://www.c-jump.com/CIS77/CPU/x86/X77_0050_add_opcode.htm オペコードの唯一の6つのMSBバイトはニーモニックを表しますが、通常のインストラクションでは、彼らが何を言っているかに応じてこのように見えます。私は、これらの正規のケースをどのようにして、これらの6つのMSBを使用して、ニーモニックを自分の例のように判断できるかを尋ねています。 – Jorayen