8080 アセンブリ用の逆アセンブラを作成しています。間違っている場合は訂正してください。バイナリをバイト単位で読み取り、各バイトをコマンドに変換するだけです。または、コマンドの長さが長くなる条件がありますか (バイナリで)。
2 に答える
なんでdosタグつけてるの?8080じゃなくて8088だったの?
どちらの場合も、一度に 1 バイトずつ直線的に移動することは絶対にできません。これらの命令セットは両方とも可変長命令です。それらがどのように起動するか、ベクタテーブルまたはエントリアドレスを確認する必要があり、次に可能な実行パスをたどる必要があります。
線形に逆アセンブルするリセット エントリ ポイントから分岐条件付きまたは無条件分岐に到達するまで、これにより、線形に逆アセンブルするエントリ ポイントがさらに 2 つ提供されます。無条件分岐は、セクションの逆アセンブルを終了します。
どのバイトがオペコードで、どのバイトがそれらのオペコードの追加データであるかを追跡する必要があります。バイト ijklm と i がある場合、k と l はオペコードです。または、命令の最初のバイトと j と m がセカンダリ バイトであるとします。次に、kバイトが存在するアドレスへの分岐をどこかで見つけた場合、それは問題ありませんが、jが存在するバイトへの分岐を見つけた場合、それは巧妙なハッカーであるか、問題を抱えています。その問題が分解を防ぐために意図的なものであったとしても、時々驚くことではありません. 多くの場合、コンパイラで生成されたコードにはこの問題はありませんが、ハンド アセンブリ (マシン コード) では (意図しない場合に) 発生する可能性があり、時間をさかのぼるほど、ハンド コーディングされたアセンブリ/マシン コードに遭遇する可能性が高くなります。
8086 と比較すると、8080 の命令セットは、命令の長さに関しては非常に単純です。次の 3 つのケースのみがあります。
- 1 バイト命令: たとえば、
XRA A
. - 1 バイトの命令の後に 1 バイトのデータが続きます。たとえば、
MVI A,0
. - 1 バイトの命令の後に 2 バイトのデータが続きます。たとえば、
LXI B,0
.
これにより、逆アセンブラが非常に簡単になります。実際、これが私が 8080 アセンブリ言語を一般的に学んだ方法です: 私のコンピューターに組み込まれている Basic インタープリターを逆アセンブルし (Basic で書かれた逆アセンブラーを使用して多くの PEEK コマンドを使用)、その知識を使用して BIOS を構築し、次のことができるようにしました。 CP/Mをインストールします。
コードが命令の途中にジャンプする可能性があることは正しいです。Microsoft Basic インタープリターは、次のように、まさにこのトリックを使用しました。
01 2E 00
01 2E 01
01 2E 02
... code using the value of L
このシーケンスでバイト オフセット 01 を呼び出すと、レジスタ L をゼロに設定する が実行2E 00
さMVI L,0
れます。次にLXI B
、レジスタ BC を 012E と 022E に設定する 2 つの命令が続きますが、これは意味がありません (値は無視されます)。
このシーケンスでバイト オフセット 04 を呼び出すと2E 01
、が実行され、MVI L,1
レジスタ L が 1 に設定されます。次にLXI B
、レジスタ BC を 022E に設定する 1 つの命令が続きますが、これは意味がありません (値は無視されます)。
このシーケンスでバイト オフセット 07 を呼び出すと、レジスタ L が 2 に設定される が実行2E 02
さMVI L,2
れます。
つまり、オフセット 09 では、オフセット 01 が呼び出された場合は L=0、オフセット 04 が呼び出された場合は L=1、オフセット 07 が呼び出された場合は L=2 になります。各呼び出しには 3 バイトしかかからず ( CD xxx xx
)、これらの異なる L 値を設定するオーバーヘッドはわずか 9 バイトです。
この巧妙さがなければ、L (2 バイト) をセットアップし、L (3 バイト) を使用しているルーチンの先頭にジャンプするために 15 バイトを使用するか、呼び出し元が L をセットアップする必要があったでしょう。これは、ルーチンへの各呼び出しが 3 ではなく 5 バイト (L のセットアップに 2、呼び出しの作成に 3) を必要とすることを意味します。
8080 分解の楽しみの 1 つは、これらのトリックを発見することです!