IA-32コードのデコードは困難な作業です。 これを確認するには、 Intel Software Development Manualまたは以前にハブで書かれた記事: IA-32コマンドシステムのプレフィックス、 逆アセンブラは正常に動作しますか? 。 機能的に正確なフルプラットフォームシミュレーターWind River Simicsがこのタスクにどのように取り組んでいるかを見てみましょう。1つのボードから始まり、マルチプロセッサ、マルチコア、さらにはマルチマシンシステム全体で終わる電子システムを定義、開発、起動できる高性能仮想環境を作成できます。 。
IA-32命令をデコードするためのほとんどのライブラリは、オペレーションコードと命令間の対応表を生成または使用します。 このアプローチの使用例は、 DIY逆アセンブラーの記事に記載されています。 ただし、接頭辞と引数のデコードは通常、手書きです: libopcodes 、 metasm 、 beaengine 、 distorm 。 このアプローチには重大な欠点があります。新しい命令セットのサポートを追加するには、多くの手作業が必要です。
GDSL言語を使用するなど、デコーダを作成する方法は他にもあります。 このアプローチは普遍的であり、あらゆるアーキテクチャのデコーダーを作成できます。
Simicsは、個別のデコードと呼ばれる、IA-32命令を扱うために、まったく異なるアプローチを使用しています。 Simicsには外部デコーダーを使用する機能もありますが、これについては後で詳しく説明します。
デコーダープロシージャの入力と出力
実際のプロセッサでは、マイクロサーキットのロジック要素の個別のブロックがデコードタスクを担当します。 シミュレータでは、プログラミング言語で書かれたいくつかの手順に対応しています。 何が彼女のインプットになり、どのような結果が彼女に期待されるべきかを考えてください。
明らかに、コマンドをフェッチする段階( eng。Fetch )で受信した既知の長さのバイトの配列がデコーダー入力に送られます。 さらに、彼は現在のプロセッサモードに注意する必要があります( IA-32コマンドシステムのプレフィックスを参照)。
作業の結果として、デコーダーはエラーコードとシーケンス分析結果を結果フィールドのリストの形式で返す必要があります。 エラーコードには次の値が可能です。
- デコードに成功しました(リターンコードは命令の長さ> 0に等しい)。 バイト配列は有効な命令として認識され、フィールドのリストにはオペレーションコードとその引数に関する情報が含まれています。
- デコードは成功しません(コード0)。 アーキテクチャで定義されている単一の命令は、入力バイト配列と一致しません。 同時に、結果フィールドの内容は意味がありません。 次に、実行段階でこの状況で何が起こりますか? それはアーキテクチャに依存します。 ほとんどの場合、デコードできないと例外が生成され、場合によっては、誤った命令がNOP(操作の不在)として解釈される可能性があります。
- 可変命令長のISAの場合、3番目の状況が発生する可能性があります-入力データは明確な決定を下すのに十分ではありません(コード<0)。 つまり、命令の一部のみがデコーダ入力に送信され、メモリ内のどのバイトに進むかについての情報がないため、これを報告します。
次の図は、フェッチフェーズとデコードフェーズの反復を組み合わせて、可変長命令のデコードを可能にするアルゴリズムの例を示しています。
個別のデコード
このアプローチの主なアイデアは、デコードフェーズを2つの段階に分けることです。
- プレフィックスのデコード。 この段階には、すべてのプレフィックスのデコードとそれらの間の競合のチェックの両方が含まれます。
- 命令コードとオペランドのデコード。 この段階では、 SimGenを使用して生成されたデコーダーを呼び出します。
言うまでもなく、第2フェーズは結果に依存します。IA-32コマンドシステムには、実際にはオペレーションコードの一部である必須プレフィックスなどがあります( IA-32コマンドシステムのプレフィックスを参照)。
外部デコーダーを使用する
Simicsでは、シミュレーターに付属のモデルビルダーユーザーガイドで説明されている外部インターフェイスを使用して、追加のデコーダーを接続できます。 したがって、多くの外部デコーダーを接続し、一部のデコーダーが肯定的な結果を返すか、デコーダーのリストが終了しない限り、それらを1つずつ呼び出すことができます。 この場合、このモデルではこのオペレーションコードは無効と見なされると結論付けることができます。
柔軟性を提供するために、Simicsの外部デコーダーは2つのタイプに分けられます。
- ユーザーデコーダーは、既存のオペレーションコードをオーバーライドできるデコーダーであり、もちろん、新しい命令をデコードする機能を追加することもできます。
- 拡張デコーダー( Eng。拡張デコーダー)-組み込みデコーダーの機能を拡張する、つまりサポートされていない命令をデコードするように設計されたデコーダー。
提案されたタイプのデコーダーの違いは、カスタムデコーダーが最初に起動されることです-ビルトインコールの前であっても、元のモデルに配線されたデコード結果を再定義できます。 拡張機能は、ユーザーも組み込みのデコーダーも命令を認識できない場合にのみ起動されます。
そしてもう1つの明らかなポイント
ユーザーデコーダーはユーザーが定義しますが、拡張デコーダーはモデルに「接続」され、変更できません。
つまり、ユーザーは、ISAを開発しているときに、元のプロセッサモデルを変更することなく、単にデコーダーをスリップして、何が変化するかを確認できます。
例
突然、NOPとHLTの命令を入れ替えて、システムが機能するかどうかを確認したいと思いました。 これを行うには、0x90をHLT、0xF4をNOPとしてデコードする小さなデコーダーを作成し、Simicsにアタッチしてシステムの起動を試みます。
さらに、このアプローチにより、既存のデコーダーをゼロから作成する代わりに再利用できるため、モデルの開発時間が大幅に短縮されます。