摘要:
引用了
Class檔案結構
前言
1.最近在學習關於虛擬機器的知識,整理一份比較詳細的class檔案結構。
2.翻譯class檔案就可以稱為直譯器
3.你可以使用javap -v Hello.class 命令去檢視class類檔案結構
4.可以從你的目標目錄和安裝目...
引用了
ofollow,noindex">Class檔案結構
前言
1.最近在學習關於虛擬機器的知識,整理一份比較詳細的class檔案結構。
2.翻譯class檔案就可以稱為直譯器
3.你可以使用javap -v Hello.class 命令去檢視class類檔案結構
4.可以從你的目標目錄和安裝目錄的rt.jar中讀取基本夠用的class檔案
讀取位元組碼
private fun getClassBit(goal: String): ByteArrayBean {
var result = getFromJar("/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/rt.jar", goal)
if (result == null) {
result = getFromFile("/Users/haha/Downloads/", goal)
}
return ByteArrayBean(result, 0)
}
private fun getFromJar(path: String, goal: String): ByteArray? {
val zipInputStream = ZipInputStream(FileInputStream(path))
val zipFile = ZipFile(path)
var zipEntry: ZipEntry?
while (true) {
zipEntry = zipInputStream.nextEntry
if (zipEntry == null) {
break
}
if (zipEntry.name == goal.plus(".class")) {
return zipFile?.getInputStream(zipEntry).readBytes()
}
}
return null
}
private fun getFromFile(path: String, goal: String): ByteArray {
val file = File("$path$goal.class")
return file.readBytes()
}
Class類檔案結構
名稱 |
變數 |
長度/Byte |
魔數 |
magic |
4 |
次版本號 |
minor_version |
2 |
主版本號 |
major version |
2 |
常量數 |
constant_num |
2 |
常量池 |
constant_pool |
常量*(constant_num - 1) |
訪問標誌 |
access_flags |
2 |
類索引 |
this_class |
2 |
父類索引 |
super_class |
2 |
介面數量 |
interface_num |
2 |
介面池 |
interface_pool |
介面*(interface_num) |
變數數量 |
field_num |
2 |
變數池 |
field_pool |
變數*(field_num) |
方法數量 |
method_num |
2 |
方法池 |
method_pool |
方法*(method_num) |
附加屬性數量 |
attribute_num |
2 |
附加屬性池 |
attribute_pool |
附加屬性*(attribute_num) |
常量結構
名稱 |
變數 |
長度/byte |
型別 |
type |
1 |
內容 |
content |
不固定,由下表決定 |
型別值 |
名稱 |
格式 |
長度/bytes |
說明 |
1 |
UTF8 |
length |
2 |
長度 |
|
|
Text |
length |
內容 |
3 |
Int |
|
4 |
值 |
4 |
Float |
|
4 |
值 |
5 |
Long |
|
8 |
值 |
6 |
Double |
|
8 |
值 |
7 |
Class |
index |
2 |
指向index位置的utf8常量 |
8 |
String |
index |
2 |
指向index位置的utf8常量 |
9 |
Fieldref |
class index |
2 |
指向index位置的class常量 |
|
|
nameAndType index |
2 |
指向index位置的nameAndType常量 |
10 |
Methodref |
class index |
2 |
指向index位置的class常量 |
|
|
nameAndType index |
2 |
指向index位置的nameAndType常量 |
11 |
Interface Methodref |
class index |
2 |
指向index位置的class常量 |
|
|
nameAndType index |
2 |
指向index位置的nameAndType常量 |
12 |
NameAndType |
name index |
2 |
指向index位置的utf8常量 |
|
|
type index |
2 |
指向index位置的utf8常量 |
備註:當常量池出現long時,constant_pool應該跳過一位,例如constant_pool[16]=1280977330748,下一位應該給constant_pool[18]賦值,原因未知,double未測試,測試class檔案為String.class
介面結構
名稱 |
長度 |
Interface Classref Index |
2 |
備註:介面池存的很簡單,只是指向常量池中介面類的索引
變數結構
名稱 |
變數 |
長度/bytes |
訪問標誌 |
access_flags |
2 |
變數名索引 |
name_index |
2 |
變數型別索引 |
descriptor_index |
2 |
附加屬性數量 |
attribute_num |
2 |
附加屬性池 |
attribute_pool |
附加屬性*(attribute_num) |
方法結構
名稱 |
變數 |
長度/bytes |
訪問標誌 |
access_flags |
2 |
方法名索引 |
name_index |
2 |
方法型別索引 |
descriptor_index |
2 |
附加屬性數量 |
attribute_num |
2 |
附加屬性池 |
attribute_pool |
附加屬性*(attribute_num) |
附加屬性結構
名稱 |
變數 |
長度/bytes |
屬性名索引 |
name_index |
2 |
長度 |
length |
4 |
內容 |
attribute_pool |
length |
根據name_index指向的屬性決定,屬性bean可能為不同格式,不同長度
方法結構-附加屬性-Code屬性(屬於附加屬性,包含附加屬性)
名稱 |
變數 |
長度/bytes |
最大棧深度 |
stack_length |
2 |
區域性變量表大小 |
localproperty_num |
2 |
指令長度 |
order_length |
4 |
指令集 |
order_array |
order_length |
異常數量 |
exception_num |
2 |
異常池 |
exception_pool |
異常屬性*exception_num |
附加屬性數量 |
attribute_num |
2 |
附加屬性池 |
attribute_pool |
附加屬性*(attribute_num) |
方法結構-附加屬性-Code屬性-異常屬性
名稱 |
變數 |
長度/bytes |
起始指令位置 |
from |
2 |
結束指令位置 |
to |
2 |
目標指令位置 |
target |
2 |
異常型別 |
type |
2 |
已知附加屬性
屬性名 |
class |
field |
method |
method-code |
Signature |
* |
* |
* |
|
Code |
|
|
* |
|
LineNumberTable |
|
|
|
* |
LocalVariableTable |
|
|
|
* |
StackMapTable |
|
|
|
* |
Deprecated |
|
|
* |
|
RuntimeVisibleAnnotations |
|
|
* |
|
Exceptions |
|
|
* |
|
SourceFile |
* |
|
|
|
InnerClasses |
* |
|
|
|
類訪問標誌符
方法訪問標誌符