2017-09-14 5 views
0

私はx86デコーダを作成していますが、命令のニーモニックを計算する効率的な方法を理解しています。x86デコード命令opcodeバイト

オペコード6のMSBがオペコードビットであることは知っていますが、ニーモニックテーブルでこれらの6ビットを使用する場所を見つけることはできません。私が見つける唯一のニーモニックテーブルは、6つのMSBだけでなく、オペコードバイト自体全体です。

オペコードバイトにエンコードされたニーモニックのデコードを効率的に行う方法と、オペコードバイト全体ではなく6つのMSBを使用するテーブル参照があるかどうか調べてみたいです。

+0

下位2ビットもopcodeの一部です...たとえば、['jcc'](http://felixcloutier.com/x86/Jcc.html)の命令では、opcodeの値が0x70から0x70になるごとに異なるニーモニックがあります。 0x7F。実際には、ModR/Mバイトからの '/ r'フィールドがオペコードの一部であることもあります。 (例えば 'shl'対' shr')。 –

+0

最新のx86マシンコードの問題点は、効率的で簡単な方法ではないことです。たとえば 'rep nop'は実際には' pause'としてデコードされ、 'rep bsf'は' tzcnt'としてデコードされます(BMI1がサポートされていれば 'bsf'としてデコードされます)。したがって、他の指示の必須プレフィックスを確認する必要があります。 –

+0

@PeterCordes私が使用していたリソースの1つはhttp://www.c-jump.com/CIS77/CPU/x86/X77_0050_add_opcode.htm オペコードの唯一の6つのMSBバイトはニーモニックを表しますが、通常のインストラクションでは、彼らが何を言っているかに応じてこのように見えます。私は、これらの正規のケースをどのようにして、これらの6つのMSBを使用して、ニーモニックを自分の例のように判断できるかを尋ねています。 – Jorayen

答えて

1

しかし、ニーモニックのテーブルを重複なく保存する効率的な方法はありませんか?

これはアルゴリズムとデータ構造の問題になっています。

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 noppause)。また、AVX VEXプレフィックスは、他の命令の無効な符号化であったものを使用します。 x86は、現在のすべての拡張機能の完全な仕事をしたいのであれば、デコードするのは非常に夢中です。

実際には、には、関数ポインタのテーブルを使用するのが最も簡単で(効率的かもしれません)。またはconst char* mnemonicint (*decode)(const char*mnemonic, const char *insn_bytes, unsigned prefix_bitmap)という関数を持つ構造体なので、多くのオペコードが同じデコード関数を指し示すことができますが、それでもニーモニックは異なります。場合によっては、渡されたニーモニックは無視されますが、それ以外の時間はすべて必要です。多くのデコード関数が呼び出すアドレス指定モードをデコードするための共通の機能を持っています。

これは、動的再コンパイルを行う代わりに、解釈するx86エミュレータを実装する方法とかなり似ています。共通のデコードループとその後の関数ポインタのディスパッチ。


使用する可能性のあるさらに複雑なデータ構造は、radix trie別名プレフィックスツリーです。 https://en.wikipedia.org/wiki/Trie#Bitwise_triesも参照してください。

密度が非常に高く、ルックアップテーブルがはるかに理にかなっているため、これは愚かなシーズンになりつつあります。(未定義のオペコードはほとんどありません)。

+0

私はパフォーマンス(速度)を目指しているだけで256エントリテーブルを格納すると言うのが最善の選択でしょうか?なぜ構造体が必要なのでしょうか?私はおそらくすべてのニーモニックの列挙型を作成し、この列挙型のインデックステーブルとして256エントリテーブルを作成すると思った、あなたの考えは? – Jorayen

+0

ええ、私は256のエントリテーブルが最高の性能を発揮すると思います。余分なデコードステップを選択するための余分な分岐はそれに値することはまずありません。 –

+0

@Jorayen:別の特殊なケースのために別のテーブルを持っていない限り、構造体を使ってニーモニックを保持し、残りのバイトをオペランドにデコードする方法を教えてください。 (例えば、 'jcc' /' call'対 'add'と' mul r/m32'と 'imul r、r/m32、imm32'と他の特殊なケース)。特別な場合には、3つのopcodeビットがModR/Mの '/ r'フィールドから来て、それを示すために(例えば別のテーブルへのポインタを使って)。あなたがすべてのアクセスでメンバーのほとんどを使用する1つの構造体を持つことは、良好な空間的局所性を与えるので、よくキャッシュされます。 –

関連する問題