類別檔案是由 JVM 讀取的大端序二進位結構。其開頭為
0xCAFEBABE,後面接著 u2 次要版本號與主要版本號。JVM 僅接受
其實作所定義的版本;類別檔案剖析器必須
拒絕不支援的版本,而不能假設較新的檔案具有
向後相容性。
頂層結構 #
在魔術數字與版本之後,檔案包含:
constant_pool_count與具有索引的常數池項目;- 類別的
access_flags、this_class與super_class; - 介面索引;
field_info結構;method_info結構;以及- 類別層級的
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 上閱讀或評論(發表評論需要登入)