編集:それをより読みやすくすることを望んでいます。
ハードウェアは、メモリを組織化されていないバイトの長いリストとは見なしません。固定ワード長または可変ワード長のすべてのプロセッサには、特定のブート方法があります。通常、ブートコードの最初の命令へのアドレスまたは最初の命令自体のいずれかを持つプロセッサメモリ/アドレス空間内の既知のアドレス。そこから、すべての命令について、現在の命令のアドレスがデコードを開始する場所になります。
たとえば、x86の場合、最初のバイトを確認する必要があります。そのバイトのデコードによっては、さらにオペコードバイトを読み取る必要がある場合があります。命令がアドレス、オフセット、またはその他の形式の即時値を必要とする場合、それらのバイトもそこにあります。プロセッサは非常に迅速に、この命令のバイト数を正確に認識します。デコードにより、命令に5バイトが含まれ、アドレス0x10で開始されたことが示されている場合、次の命令は0x10+5または0x15にあります。これは永遠に続きます。無条件分岐は、プロセッサによってさまざまな種類がありますが、命令に続くバイトが別の命令であるとは限りません。条件付きまたは無条件の分岐は、別の命令または一連の命令がメモリ内で開始する手がかりを提供します。
今日のX86は、命令をデコードするときに一度に1バイトをフェッチしないことに注意してください。適切なサイズの読み取りが発生し、おそらく一度に64ビットであり、プロセッサは必要に応じてバイトをそこから引き出します。最新のプロセッサから1バイトを読み取る場合、メモリバスはフルサイズの読み取りを実行し、メモリコントローラが後のビットのみをプルするバス上のすべてのビットを表示するか、そのデータを保持するまでになります。 。連続したアドレスに2つの32ビット読み取り命令があるが、メモリインターフェイスで1つの64ビット読み取りのみが発生するプロセッサがいくつかあります。
逆アセンブラやエミュレータを作成することを強くお勧めします。固定長の命令の場合、それは非常に簡単です。最初から始めて、メモリを通過するときにデコードするだけです。固定ワード長の逆アセンブラは、このプロセスの一部であるデコード命令について学習するのに役立つ場合がありますが、可変ワード長の命令に従う方法と、整列から外れることなくそれらを分離する方法を理解するのに役立ちません。
MSP430は、最初の逆アセンブラとして適しています。gnuツールasmやCなど(さらに言えばllvm)があります。アセンブラから始めてCにするか、事前に作成されたバイナリをいくつか使用します。重要なのは、プロセッサのようにコードをウォークスルーし、リセットベクトルから始めて、ウォークスルーする必要があるということです。1つの命令をデコードすると、その長さがわかり、無条件分岐に到達するまで次の命令がどこにあるかがわかります。プログラマーが逆アセンブラをだますために意図的にトラップを残していない限り、すべてのブランチが条件付きまたは無条件で有効な命令を指していると想定してください。午後または夕方は、すべてを打ち負かすか、少なくとも概念を理解するために必要なすべてです。必ずしも命令を完全にデコードする必要はありません。これを本格的な逆アセンブラにする必要はありません。命令の長さを決定し、それがブランチであるかどうか、そしてブランチである場合はどこであるかを決定するのに十分なだけデコードする必要があります。16ビット命令であるため、必要に応じて、可能なすべての命令ビットの組み合わせとその長さのテーブルを一度に作成できます。これにより、時間を節約できます。あなたはまだ枝を通り抜ける道を解読しなければなりません。
一部の人々は再帰を使用するかもしれません、代わりに私はどのバイトが命令の始まりであるか、どのバイト/ワードが命令の一部であるが最初のバイト/ワードではないか、そして私がまだデコードしていないバイトを示すメモリマップを使用します。まず、割り込みとリセットのベクトルを取得し、それらを使用して命令の開始点をマークします。次に、命令をデコードしてさらに開始点を探すループに入ります。パスが他の開始点なしで発生した場合、私はそのフェーズを終了しました。いずれかの時点で、命令の途中にある命令の開始点を見つけた場合、解決するには人間の介入が必要な問題があります。たとえば、古いビデオゲームのROMを逆アセンブルすると、手書きのアセンブラーが表示される可能性があります。コンパイラによって生成された命令は、非常にクリーンで予測可能である傾向があります。命令のクリーンなメモリマップと残っているものでこれを乗り越えれば(データを想定)、命令がどこにあるかを知って1つのパスを作成し、それらをデコードして印刷できます。可変ワード長命令セットの逆アセンブラが実行できないことは、すべての命令を見つけることです。命令セットに、たとえばジャンプテーブルや、実行用の実行時計算アドレスがある場合、実際にコードを実行しないと、それらすべてを見つけることはできません。
そこには多くの既存のエミュレーターと逆アセンブラーがあります。自分で作成するのではなく、従うことを試みたい場合は、私自身http://github.com/dwelch67をいくつか持っています。
可変および固定の単語長には賛否両論があります。Fixedには確かに利点があり、読みやすく、デコードしやすく、すべてが素晴らしく適切ですが、RAM、特にキャッシュについて考えると、ARMと同じキャッシュにさらに多くのx86命令を詰め込むことができます。一方、ARMははるかに簡単にデコードでき、ロジックや電力などがはるかに少なくて済みます。歴史的に、メモリは高価でしたロジックは高価でした、そしてあなたが行くにつれてバイトはそれがどのように機能したかでした。1バイトのオペコードでは256命令に制限されていたため、とにかく可変ワード長にしたイミディエートとアドレスは言うまでもなく、より多くのバイトを必要とする一部のオペコードに拡張されました。何十年にもわたって下位互換性を維持すると、現在の場所に行き着きます。
この混乱のすべてに追加するために、たとえばARMには可変ワード長の命令セットがあります。Thumbには単一の可変ワード命令であるブランチがありましたが、これは固定長として簡単にデコードできます。しかし、彼らは、可変ワード長の命令セットに実際に似ているthumb2を作成しました。また、32ビットARM命令をサポートするプロセッサの多く/ほとんどは16ビットサム命令もサポートしているため、ARMプロセッサを使用しても、データをワードごとに整列してデコードすることはできず、可変ワード長を使用する必要があります。さらに悪いことに、ARMからサムへの遷移は実行によってデコードされます。通常、単純に分解してサムからアームを把握することはできません。混合モードのコンパイラで生成された分岐では、分岐するアドレスをレジスタにロードしてから、bx命令を使用して分岐することがよくあります。