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 並非對每種 類別檔案類型都具有意義或合法。

常數池與名稱 #

常數池的索引從一開始;除非特定結構保留索引零,否則該索引無效。 CONSTANT_Long 與 CONSTANT_Double 會占用 兩個連續索引,其中第二個不可使用。項目包括基本型別 與字串常數、Class、String、欄位、方法與介面方法 參照、名稱與型別配對、方法控制代碼與方法型別、動態及 invoke-dynamic 呼叫位置、模組,以及套件。參照採符號形式: 例如,CONSTANT_Methodref 會經由類別及名稱與型別 項目指向目標,而非指向記憶體中的方法。

類別檔案名稱使用斜線分隔的內部名稱,例如 java/lang/String;面向原始碼的 API 則以點號表示二進位名稱。欄位與 方法描述元會編碼型別,例如 Ljava/lang/String;、[I 與 (I[Ljava/lang/String;)V。CONSTANT_Utf8 使用類別檔案的修改版 UTF-8 編碼,其中會將空字元編碼為 C0 80,並個別表示 UTF-16 代理碼元。它不能與一般 UTF-8 解碼器交替使用。

成員與屬性 #

每個 field_info 與 method_info 都具有存取旗標、名稱與描述元 索引,以及屬性表。方法的 Code 屬性儲存 max_stack、max_locals、位元組碼、例外處理常式,以及巢狀屬性, 例如行號或堆疊對應框架。欄位可帶有 ConstantValue; 類別與成員透過屬性攜帶中繼資料,包括註解、 簽章、巢狀結構資訊、記錄、模組與除錯資料。未知 屬性只能依據其宣告長度略過;不能從名稱 推測其語意。

安全剖析 #

即使類別檔案來自建置程序,也應將其視為不受信任的輸入。每次 讀取之前,驗證剩餘位元組數;驗證每項計數、索引、 標籤、旗標組合、描述元與屬性長度;使用經檢查的算術運算 計算位移加長度;並拒絕結尾處的結構不一致。解析符號參照之前, 應強制執行格式的版本與情境規則。 驗證器會加入執行安全檢查,但不能取代 具有界限檢查的二進位剖析器。

javap -v 等工具可顯示解碼後的內容,但轉換操作應使用 持續維護、支援目標類別檔案版本,並能在必要時保留 未知屬性的程式庫。

參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)