td6502 - 6502逆アセンブラ

精度を追求した6502逆アセンブラです。

ダウンロード: td6502-0.1.1.tar.bz2

特徴

  • 主用途としてNESソフトの解析を想定
  • 制御フロー解析によりコード/データ判定を行う
  • ルーチン境界やコード/データ境界を認識し、適切に空行を挿入
  • ルーチンのエントリポイントと思われる箇所にラベルを付加
  • 割り込みアドレスの推測(明示的指定や無効化も可能)
  • コード/データ領域の明示的な指定も可能(FCEUX CDLからの変換スクリプト付属)

md6502 のようなマッパー別コメント付加機能はありません。

使い方

バンク単位で逆アセンブルを行うので、NESソフトの場合は予めPRG-ROMをバンク分割 しておく必要があります。

コマンドライン:

Usage: td6502 [options] <infile>
  --addr-start ADDR   開始アドレス (設定ファイルに記述しない場合は必須)
  --int-nmi ADDR      NMI割り込みアドレス (デフォルトは自動推測、"none" を指定すると無効)
  --int-reset ADDR    RESET割り込みアドレス (デフォルトは自動推測、"none" を指定すると無効)
  --int-irq ADDR      IRQ割り込みアドレス (デフォルトは自動推測、"none" を指定すると無効)
  --config CFG        設定ファイル
  --output PATH       出力ファイル (デフォルトは標準出力)
  --help              ヘルプを表示

設定ファイル:

# 設定ファイルのサンプル
# 行内で '#' より後ろにある文字は無視されます。
addr_start    C000    # 開始アドレス
int_nmi       C000    # NMI割り込みアドレス ("none" を指定すると無効)
int_reset     C100    # RESET割り込みアドレス ("none" を指定すると無効)
int_irq       C200    # IRQ割り込みアドレス ("none" を指定すると無効)
usage_code    C000    C2FF    # $C000-$C2FF をコード指定
usage_data    byte    C300    C3FF    # $C300-$C3FF をデータ指定 (1Byte単位)
usage_data    le16    C400    C4FF    # $C400-$C4FF をデータ指定 (2Byte単位、リトルエンディアン)

コード/データ指定は閉区間です。また、コード/データ兼用領域が存在してもかまい ません。

技術的詳細

制御フロー解析においては、いわゆる隠し命令およびその他いくつかの命令は不正と みなし、そのような命令を含む制御フローは無効とすることでコード/データ判定を 行っています(商用NESソフトでは隠し命令は滅多に使われません)。ただし、明示的 なコード指定を行えば隠し命令などもコードとして逆アセンブルできます。

単にバイト列を先頭からなめる方式のものよりは高精度なはずですが、完璧ではあり ません。以下のような問題により、コード/データ判定を誤ることがあります:

データ内に含まれるコード終端要素
データ内に RTS, JMP などと解釈できるバイト列が存在する場合、データをコー ドと誤認する可能性があります。
無条件分岐
明示的なコード/データ指定がない場合、分岐命令は真/偽どちらもありうるもの として解析されます。よって、実質的に無条件分岐である分岐命令を含むコード は正しく解析できません。
間接ジャンプ
間接ジャンプの飛び先は解析できません(原理的に無理)。よって、間接ジャンプ のみで呼び出されるコードは正しく解析できません。
スタック操作
スタック操作のトレースは行っていません。よって、スタック操作によって戻り アドレスを変化させるようなコードは正しく解析できません。
オペコード/オペランド問題
未解析領域から明示的にコード指定されている領域へジャンプする場合、本来オ ペコードではないバイトをオペコードと誤認する可能性があります。これにより、 本来データであった未解析領域をコードと誤認する可能性があります(本来はコー ド領域を指定するのでなく、「どのバイトがオペコードか」を指定するようにす べきなのですが、FCEUX CDLではこの情報は記録できないので…)。

他にも、解析に伴う微妙な問題があります:

不正命令の基準
隠し命令以外にも滅多に使われない命令があるので、そうした命令を不正とする ことで精度を向上させられる可能性があります。本プログラムでは BRK は無条 件で不正命令とし、RTI についてはNMI/IRQアドレスから開始する制御フローに 対してのみ有効としています。
命令のオーバーラップ
本プログラムは、あるバイトがオペコードとオペランドを兼ねることがありうる という前提で解析を行います。このようなコードは稀ですが実際に存在します (例: 任天堂『ゴルフ』ルーチン $D422)。
単独の RTS
これは間接ジャンプの飛び先として使われることもあるので微妙なところですが、 これを許すとデータ領域を正しく解析できないことが多いため、本プログラムで はコードとはみなしていません。

結局のところ、自動解析のみで完璧にコード/データ判定を行うのは無理があるので、 完璧な結果が欲しければFCEUX CDLなどを駆使して明示的なコード/データ指定を行う か、逆アセンブル結果を手で修正する必要があります。

更新履歴

0.1.1

強制コード指定された制御フローの途中で強制データ指定にぶつかった場合は矛 盾とはみなさず、その直前までをコードとみなすようにした(ギャラクシアンの $E44B 呼び出しを含むコードを正しく解析するため)

その他細かい修正

0.1.0
作った

TODO

コメント
コメントを外部ファイルとして与えられればコメントつきのソースコードを共有 できる。diff などを使う方法だと、逆アセンブラの出力形式変更に対応できな い。
シンボルテーブル
シンボルテーブルを外部ファイルとして与えられれば便利そう。ただし配列など の型を持つ変数、およびバンク切り替えがある場合にアドレスと名前が1対1対応 にならない問題について考慮する必要がある。
アドレスごとのパーミッション
ミラー領域を読み書きしたり、読み取り専用I/Oポートに書き込んだり、I/Oポー ト領域を実行したりするのは明らかに不正なので、こういうのはコードとみなさ ないようにすれば若干精度が上がるはず。ただしマッパーの知識が必要になるの であまりやる気なし。

Back