JVM クラスファイル形式

最終更新: 2024-11-18 19:52:43 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

クラスファイルは、JVM が使用するビッグエンディアンのバイナリー構造です。先頭は 0xCAFEBABE で、その後に u2 のマイナーバージョンとメジャーバージョンが続きます。JVM が受け入れるのは、その実装に対して定義されたバージョンだけです。クラスファイルパーサーは、新しいファイルに後方互換性があると仮定せず、サポート対象外のバージョンを拒否する必要があります。

最上位構造 #

マジック値とバージョンの後に、ファイルには次の要素が含まれます。

  1. constant_pool_count とインデックス付きの定数プールエントリー。
  2. クラスの access_flags、this_class、super_class。
  3. インターフェースのインデックス。
  4. field_info 構造体。
  5. method_info 構造体。
  6. クラスレベルの attribute_info 構造体。

カウントは符号なし u2 値ですが、属性の attribute_length は u4 です。アクセスフラグはコンテキストを記述します。ACC_PUBLIC、ACC_FINAL、ACC_SUPER、ACC_INTERFACE、ACC_ABSTRACT、ACC_SYNTHETIC、ACC_ANNOTATION、ACC_ENUM、ACC_MODULE のすべてが、あらゆる種類のクラスファイルで意味を持つ、または正当であるわけではありません。

定数プールと名前 #

定数プールのインデックスは 1 から始まります。特定の構造で予約されている場合を除き、インデックス 0 は無効です。CONSTANT_Long と CONSTANT_Double は連続する 2 つのインデックスを使用し、2 番目は使用できません。エントリーには、プリミティブ定数と文字列定数、Class、String、フィールド参照、メソッド参照、インターフェースメソッド参照、名前と型のペア、メソッドハンドルとメソッド型、dynamic および invoke-dynamic コールサイト、モジュール、パッケージが含まれます。参照はシンボル形式です。たとえば、CONSTANT_Methodref はメモリー内のメソッドではなく、クラスエントリーおよび名前と型のエントリーを介して参照します。

クラスファイルの名前には、java/lang/String のようにスラッシュで区切られた内部名を使用します。ソース指向 API のバイナリー名はドットを使用します。フィールドおよびメソッドのディスクリプターは、Ljava/lang/String;、[I、(I[Ljava/lang/String;)V などの形式で型をエンコードします。CONSTANT_Utf8 はクラスファイルの修正 UTF-8 エンコーディングを使用します。このエンコーディングは null 文字を C0 80 としてエンコードし、UTF-16 のサロゲートコード単位を個別に表現します。汎用 UTF-8 デコーダーと交換可能ではありません。

メンバーと属性 #

各 field_info と method_info には、アクセスフラグ、名前およびディスクリプターのインデックス、属性テーブルがあります。メソッドの Code 属性には、max_stack、max_locals、バイトコード、例外ハンドラー、および行番号やスタックマップフレームなどのネストされた属性が格納されます。フィールドは ConstantValue を持つ場合があります。クラスとメンバーは、アノテーション、シグネチャー、nest 情報、レコード、モジュール、デバッグデータなどの属性を通じてメタデータを保持します。未知の属性をスキップできるのは、宣言された長さを使用する場合だけです。名前からセマンティクスを推測することはできません。

安全な解析 #

ビルドから生成された場合でも、クラスファイルを敵対的な入力として扱ってください。読み取りのたびに残りのバイト数を検証し、すべてのカウント、インデックス、タグ、フラグの組み合わせ、ディスクリプター、属性長を検証し、オフセットと長さの加算には検査付き算術演算を使用し、末尾の構造的不整合を拒否してください。シンボル参照を解決する前に、形式のバージョン規則とコンテキスト規則を適用します。ベリファイアは実行安全性の検査を追加しますが、有界なバイナリーパーサーの代わりにはなりません。

javap -v などのツールはデコード済みのビューを表示しますが、変換には、対象のクラスファイルバージョンをサポートし、必要に応じて未知の属性を保持する、保守されたライブラリを使用すべきです。

参考資料 #

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)