

dconstruct は、The Last of Us Part II で使用されている DC-Script ファイルのためのリバースエンジニアリングツールです。逆アセンブラと逆コンパイラを備えています。
逆アセンブルされた構造体とバイトコードを含む.asmファイル、およびCライクな疑似コードを含む.dcpl(DC疑似言語)ファイルを出力します。
また、コマンドラインからファイルを編集することもでき、構造全体を簡単に置き換えることもできます。これにより、.binファイル内のいくつかの値を変更するだけのMODを非常に簡単に作成できます。
-e フラグを使用して編集を行い、MODに使用できる新しいファイルを作成まず、解凍した dconstruct ディレクトリを C:\Program Files などの安全な場所に移動することをお勧めします。
dconstruct をできるだけ使いやすくするために、dconstruct フォルダ内の .\bin ディレクトリを PATH に追加することをお勧めします。詳細はこちらをご覧いただくか、以下の簡単な手順に従ってください。

dconstruct --about と入力します。プログラムからの出力が表示され、エラーメッセージが表示されないはずです。以下のようなコマンドをコマンドラインで実行して、最初の逆アセンブルファイルを生成します:```shell dconstruct my_bin_file.bin
これにより、入力ファイルと同じディレクトリに `my_bin_file.bin.asm` というファイルが出力されます。そのファイルはテキスト/コードエディタで開くことができます。VSCodeのような高度な検索機能を備え、大きなファイルの処理に優れたエディタをお勧めします。標準のWindowsメモ帳は推奨しません。
ファイルを逆コンパイルするには、コマンド実行時に `--decompile` フラグを追加します。
# コマンドライン引数
- `-i` - 入力ファイルまたはフォルダ。最初の引数として入力パスを渡す場合は省略可能。
- `-o` - 出力パス。入力パスがフォルダの場合、これはファイルにすることはできません。出力が指定されない場合、.txtファイルは入力ファイルの隣に配置されます。入力がフォルダで出力が指定されない場合、プログラムはカレントワーキングディレクトリに "output" ディレクトリを作成し、すべてのファイルをそこに配置します。
- サイドベースは実行ファイルの隣にある `sidbase.bin` から読み込まれます。
- `--no_decompile` - 逆コンパイルされた疑似コードを .dcpl ファイルに出力しない。ファイルは .asm ファイルの隣に配置されます。デフォルトは false です。
- `--no_optimize` - dcpl コードの最適化とクリーンアップを行わない。関数呼び出しのインライン化、未使用変数の削除、互換性のある for ループの foreach ループへの変換、一部の if-else チェーンの match 式への変換などが含まれます。
- `--pascal_case` - ゲームの関数名を dcpl 出力でパスカルケースに変換する。例: get-boolean -> GetBoolean。
- `--graphs` - 逆コンパイルされたすべての関数の制御フローグラフを含む .svg ファイルを出力する。各 .bin ファイルには、そのグラフのすべてを含む独自のフォルダが作成されます。これにより逆コンパイル速度が **大幅に** 低下するため、多数のファイルを同時に逆コンパイルする場合には推奨されません。
- `--emit_once` - 同じ構造が逆アセンブル内で二度出力されることを防ぎます。構造が複数回出現する場合、最初のインスタンスのみ完全に出力され、その他の箇所は `ALREADY_EMITTED` タグに置き換えられます。これによりファイルサイズを大幅に削減できます。
- `-e` - 編集を行う。詳細は以下のセクションを参照。
- `--edit_file` - 編集ファイルを指定する。編集ファイルには1行に1つの編集が含まれます。`-e` フラグと同じ構文を使用します。
# 逆アセンブラとは?
[逆アセンブラ](https://en.wikipedia.org/wiki/Disassembler) は、バイナリ命令(別名 [バイトコード](https://en.wikipedia.org/wiki/Bytecode) または [マシンコード](https://en.wikipedia.org/wiki/Machine_code))を読み取り、それぞれを [ニーモニック](https://en.wikipedia.org/wiki/Assembly_language#Mnemonics) と呼ばれる人間が読めるバージョンに変換するツールです。逆アセンブラは一般的に、これらの命令の意味についてはあまり解釈しようとせず、単に1対1で読み取り可能なバージョンに変換します。例えば、以下の命令は:```arm
15 00 00 00
4A 01 01 00
43 31 01 00
1C 00 00 01
は以下の人間が読めるバージョンに逆アセンブルされます:```arm LookupPointer r0, 0 LoadStaticU64Imm r1, 1 Move r49, r1 CallFf r0, r0, 1
All numbers in the bytecode are written in [hexadecimal](https://en.wikipedia.org/wiki/hexadecimal). The first column in each row represents the `opcode`, or the type of instruction to be executed. The next column is the destination register, where the result of the operation will be stored. The last two columns are operands 1 and 2, which are either registers or literal numbers on which the operation will be performed. Not all instructions use all 4 bytes, for example, the first `LookupPointer` instruction only needs one operand.
The dconstruct disassembler also adds some additional information meant to make reading the instructions a bit easier. It also inserts labels (e.g. `L_0`) to make branches in the code easier to trace.```arm
15 00 00 00 LookupPointer r0, 0 r0 = ST[0] -> <is-player-abby?>
4A 01 01 00 LoadStaticU64Imm r1, 1 r1 = ST[1] -> <player>
43 31 01 00 Move r49, r1 r49 = player
1C 00 00 01 CallFf r0, r0, 1 r0 = is-player-abby?(player)
2F 0D 00 00 BranchIfNot r0, 0xD IF NOT r0 => L_0
これにより、プログラムが過度な推測をせずにファイルの生の内容を確認したい場合に便利です。ただし、大規模なコードブロックの場合、構造がまったくないため読みにくくなることがあります。そこでデコンパイラの出番です。
デコンパイラはコンパイラの逆の機能を持ちます。コンパイラは、人間が書いたコード(C、Java、C++など)を受け取り、機械語命令を生成するプログラムです。TLOU2や他の多くのNDゲームでは、使用されるスクリプト言語は「DC」と呼ばれており、これは基本的にプログラミング言語Racket>)の一種です。そして「機械」とは、ゲーム自体が実行中に命令を実行するものです。基本的に、プログラマはDCを記述し、コンパイラを使ってそのコードをゲームに同梱される.binファイルに変換します。
デコンパイラは、上記の逆アセンブルされたコードを受け取り、疑似コードと呼ばれるものを生成します。疑似コードは、元のソースコードを再構築しようとする_試み_です。これによりコードの理解が大幅に容易になりますが、疑似コードの生成プロセスは非常に複雑です。なぜなら、最終的なバイトコードを生成できるソースコードのバージョンは多数あり、またコンパイル中に最適化が行われるからです。
現在、dconstructデコンパイラの出力は、元のDCと構文的には似ていません。DC(つまりRacket)は関数型プログラミング言語であり、独特の構文を持ち、それに慣れていないプログラマには非常に読みにくいものです。そのため、現時点では疑似コードをよりC言語に近い形にすることを選択しました。これにより、ほとんどの人にとって読みやすくなるはずです。ただし、Racket版やPython版など、さらに多くの構文を作成する計画があります。
43 00 31 00 15 01 00 00 43 02 00 00 43 31 02 00 1B 01 01 01 43 02 00 00 40 03 01 00 24 02 02 03 2F 0B 02 00 40 02 02 00 2D 0C 00 00 40 02 03 00 43 03 02 00 15 04 04 00 43 05 01 00 43 31 05 00 1C 04 04 01 07 03 03 04 43 01 03 00 00 01 01 00
これでは、コードの動作をほぼ把握できません。