by cloud (safesuite@263.net )
定義:u1 1個字節(jié)為單位的非負(fù)值
u2 2個字節(jié)為單位的非負(fù)值
u3 . . . . . . . . (其他以此類推 )
Java文件結(jié)構(gòu)用類似struct的描述如下:
ClassFile {
u4 magic; // 必須為: 0xCAFEBABE
u2 minor_version;
u2 major_version; //CLASS文件結(jié)構(gòu)主次版本號 JAVA2支持45.0-46.
0
u2 constant_pool_count; //記錄常量信息
cp_info constant_pool[constant_pool_count-1]; //計數(shù)從1開始
u2 access_flags; //class/interface訪問權(quán)限
u2 this_class; //指向constant_poll中的有效索引值
u2 super_class; //0或指向constant_poll中的有效索引值,對于in
terface必須為非0
u2 interfaces_count; //superinterfaces的個數(shù)
u2 interfaces[interfaces_count]; //計數(shù)[0,count-1) 對應(yīng)constant_po
ol中的一個索引值
u2 fields_count;
field_info fields[fields_count]; //主要用于記錄class及實例中的變量
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
cp_info {
u1 tag;
u1 info[];
}
tag 意義如下:
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
此時cp_info分別對應(yīng)結(jié)構(gòu)變化為
1. CONSTANT_Class
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
2. CONSTANT_Fieldref
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index; //constant_pool的索引,對應(yīng)CONSTANT_Class_
info
u2 name_and_type_index;//constant_pool的索引,對應(yīng)CONSTANT_
NameAndType_info
}
3. CONSTANT_Methodref
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
4. CONSTANT_InterfaceMethodref
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
5. CONSTANT_String
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
6. CONSTANT_Integer
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
7. CONSTANT_Float
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
8. CONSTANT_Long
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
9. CONSTANT_Double
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes
}
10.CONSTANT_NameAndType
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
11.CONSTANT_Utf8
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
access_flags意義如下:
ACC_PUBLIC 0x0001
ACC_FINAL 0x0010
ACC_SUPER 0x0020
ACC_INTERFACE 0x0200
ACC_ABSTRACT 0x0400
如果是interface那么必須置ACC_INTERFACE,如果沒有置ACC_INTERFACE則定義的是一
個類而非接口。
如果設(shè)置了ACC_INTERFACE,那么ACC_ABSTRACT位也必須被設(shè)置,當(dāng)然也可以設(shè)置AC
C_PUBLIC。
ACC_SUPER用以表明invokespecial語義,Sun公司老的JAVA編譯器沒有設(shè)置ACC_SUPER
,并且老的JVM
忽略ACC_SUPER位,但新的編譯器應(yīng)該實現(xiàn)invokespecial語義。
其他未指明的位保留將來使用,并且編譯器應(yīng)當(dāng)將其置為0,同時Java虛擬機(jī)應(yīng)當(dāng)忽
略他們。
this_class: constant_pool中的索引值,指向的元素的cp_info等價為CONSTANT_Class
_info
CONSTANT_Class_info {
u1 tag; //必須為CONSTANT_Class (7)
u2 name_index; //為指向constant_pool中的一個索引值
}
name_index :指向的元素的cp_info等價為CONSTANT_Utf8_info
CONSTANT_Utf8_info {
u1 tag; //必須為CONSTANT_Utf8 (1)
u2 length;
u1 bytes[length]; //Utf8編碼的字符串
}
field_info {
u2 access_flags; //訪問控制權(quán)
u2 name_index; //constant_pool中的索引,對應(yīng)于CONSTANT_Utf8_inf
o描述。
u2 descriptor_index; //constant_pool中的索引,對應(yīng)于CONSTANT_Utf8_i
nfo描述。
u2 attributes_count;
attribute_info attributes[attributes_count]; //attribute_info將在mo
thods后描述。
}
field_info中access_flages意義如下:
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_VOLATILE 0x0040
ACC_TRANSIENT 0x0080
其中很顯然不能同時為ACC_FINAL和ACC_VOLATILE ;且前三項是互斥的。
interface必須置ACC_PUBLIC, ACC_STATIC,ACC_FINAL位,且不能置其他位。
其他未指明的位保留將來使用,并且編譯器應(yīng)當(dāng)將其置為0,同時Java虛擬機(jī)應(yīng)
當(dāng)忽略他們。
methods指明了類中的所有方法。
method_info {
u2 access_flags;
u2 name_index; //指向constant_pool的入口,對應(yīng)為CONSTANT_
Utf8_info
u2 descriptor_index; //指向constant_pool的入口,對應(yīng)為CONS
TANT_Utf8_info
u2 attributes_count;
attribute_info attributes[attributes_count];
//此處只能出現(xiàn)Code、Exceptions、Synthetic、Deprecated四種類
型的屬性
}
access_flags訪問權(quán)描述如下:
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_SYNCHRONIZED 0x0020
ACC_NATIVE 0x0100
ACC_ABSTRACT 0x0400
ACC_STRICT 0x0800
attribute_info {
u2 attribute_name_index; //constant_pool中的索引,對應(yīng)于CONSTANT_U
tf8_info描述。
u4 attribute_length;
u1 info[attribute_length];
}
現(xiàn)在已經(jīng)預(yù)定義的屬性有:
1. SourceFile : attribute_info被替代為:
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index; //指向constant_pool中的一個CONSTANT_Ut
f8_info 結(jié)構(gòu)。
}
2. ConstantValue : attribute_info被替代為:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length; //必須為2
u2 constantvalue_index;
}
對于constantvalue_index意義如下:
long CONSTANT_Long
float CONSTANT_Float
double CONSTANT_Double
int, short, char, byte, boolean CONSTANT_Integer
String CONSTANT_String
ConstantValue用于field_info 中,用于描述一個static常量,
且此時field_info的access_flags應(yīng)為ACC_STATIC
3. Code : attribute_info被替代為:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack; //執(zhí)行此函數(shù)時可用的棧的最大深度
u2 max_locals; //執(zhí)行此函數(shù)可用到的最大本地變量數(shù)目,包括參
數(shù)。
// 注意:一個long/double相當(dāng)于2個變量數(shù)目.
u4 code_length; //本函數(shù)用到的代碼長度。
u1 code[code_length]; //實現(xiàn)本函數(shù)的真正字節(jié)碼
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc; //捕獲違例時執(zhí)行代碼數(shù)組中的[start_pc, end_p
c)部分
u2 handler_pc; //現(xiàn)在還不大明白他是干嘛的!!
u2 catch_type; //指向constant_pool的索引,對應(yīng)CONSTANT
_Class_info
}exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
CONSTANT_Class_info {
u1 tag; //必須為CONSTANT_Class (7)
u2 name_index; //不用我再說了吧?
}
Code屬性用于method_info結(jié)構(gòu)中。
4. Exceptions : attribute_info被替代為:
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
5. InnerClasses : attribute_info被替代為:
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;
u2 outer_class_info_index;
u2 inner_name_index;
u2 inner_class_access_flags;
} classes[number_of_classes];
}
6. Synthetic : attribute_info被替代為:
Synthetic_attribute {
u2 attribute_name_index; //不用廢話了吧?
u4 attribute_length; //必須為0
}
Synthetic用在 field_info、 method_info 中,
一個沒有出現(xiàn)在源程序中的變量必須使用Synthetic標(biāo)記。
7. LineNumberTable : attribute_info被替代為:
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc; //代碼數(shù)組中的開始處
u2 line_number; //源文件中的行號(對于每一非空行都有這
么一項)
} line_number_table[line_number_table_length];
}
LineNumberTable用于Code屬性中,通常用于調(diào)試。
8. LocalVariableTable : attribute_info被替代為:
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length; //當(dāng)解釋到代碼數(shù)組的[start_pc,start_pc+lengt
h]
//時變量必須被賦值??
u2 name_index;
u2 descriptor_index;
u2 index; //到本地變量數(shù)組的一個索引
} local_variable_table[local_variable_table_length];
}
9. Deprecated : attribute_info被替代為:
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length; //必須為0
}
當(dāng)然你也可以定義自己的屬性,但要你自己的編譯器和虛擬機(jī)實現(xiàn)。JVM將忽略自己
不認(rèn)可的屬性。
來實踐一下吧!
編寫一個最簡單的程序:
class Test
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
c:\work>javac Test.java
c:\work>filedump Test.class
File Dump V0.3 Beta by cloud (safesuite@363.net).
01:00 ca fe ba be 00 03 00 2d 00 1d 0a 00 06 00 0f 09 .......-........
01:01 00 10 00 11 08 00 12 0a 00 13 00 14 07 00 15 07 ................
01:02 00 16 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 .....<init>...()
01:03 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e V...Code...LineN
01:04 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69 umberTable...mai
01:05 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 n...([Ljava/lang
01:06 2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75 /String;)V...Sou
01:07 72 63 65 46 69 6c 65 01 00 09 54 65 73 74 2e 6a rceFile...Test.j
>d
02:00 61 76 61 0c 00 07 00 08 07 00 17 0c 00 18 00 19 ava.............
02:01 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 07 ...Hello World!.
02:02 00 1a 0c 00 1b 00 1c 01 00 04 54 65 73 74 01 00 ..........Test..
02:03 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 .java/lang/Objec
02:04 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 t...java/lang/Sy
02:05 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 stem...out...Lja
02:06 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 va/io/PrintStrea
02:07 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 m;...java/io/Pri
>d
03:00 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e 74 ntStream...print
03:01 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 ln...(Ljava/lang
03:02 2f 53 74 72 69 6e 67 3b 29 56 00 20 00 05 00 06 /String;)V. ....
03:03 00 00 00 00 00 02 00 00 00 07 00 08 00 01 00 09 ................
03:04 00 00 00 1d 00 01 00 01 00 00 00 05 2a b7 00 01 ............*...
03:05 b1 00 00 00 01 00 0a 00 00 00 06 00 01 00 00 00 ................
03:06 01 00 09 00 0b 00 0c 00 01 00 09 00 00 00 25 00 ..............%.
03:07 02 00 01 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 ................
>d
04:00 00 00 00 01 00 0a 00 00 00 0a 00 02 00 00 00 05 ................
04:01 00 08 00 06 00 01 00 0d 00 00 00 02 00 0e ..............
>
解讀一下:
ca fe ba be magic
00 03 00 2d 次主版本號,換算一下: 45.3 (注意,不是高字節(jié)在前,別犯職業(yè)?。?br>)
00 1d constant_pool元素個數(shù)加一 : 29 那么constant_pool就是[1-28]
constant_pool: 1-28
1. 0a 00 06 00 0f
0x0a :CONSTANT_InterfaceMethodref 0x06 :class index 0x0f :nam
e-type-index
2. 09 00 10 00 11
0x09 : CONSTANT_Fieldref 0x10: . . . 0x11 :
. . . .
3. 08 00 12 0x08 : CONSTANT_String 0x12 : string_index
4. 0a 00 13 00 14 0x0a同于1.
5. 07 00 15 0x07 : CONSTANT_Class 0x15 : name_index
6. 07 00 16
7. 01 00 06 3c 69 6e 69 74 3e 01 ...<init>
0x01 CONSTANT_Utf8 0x06 : string length "<init>" : 構(gòu)造
函數(shù)
8. 01 00 03 28 29 56 ...()V 函數(shù),無參數(shù)
0x01 . . . . . . 0x03 : . . . . "()V" : .
. .
9. 01 00 04 43 6f 64 65 ...Code
10. 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 ...LineNumberTable
11. 01 00 04 6d 61 69 6e ...main
12. 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
...([Ljava/lang/String;)V 函數(shù),參數(shù)為String[]類型
13. 01 00 0a 53 6f 75 72 63 65 46 69 6c 65 ...SourceFile
14. 01 00 09 54 65 73 74 2e 6a 61 76 61 ...Test.java
15. 0c 00 07 00 08 0x0c:CONSTANT_NameAndType 07 : name-index 08:name-t
ype-index
16. 07 00 17
17. 0c 00 18 00 19
18. 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 ...Hello World!
19. 07 00 1a
20. 0c 00 1b 00 1c
21. 01 00 04 54 65 73 74 ...Test
22. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 ...java/lang/Obj
ect
23. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d ...java/lang/Sys
tem
24. 01 00 03 6f 75 74 ...out
25. 01 00 15 4c 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b
...Ljava/io/PrintStream;
26. 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d...java/io
/PrintStream
27. 01 00 07 70 72 69 6e 74 6c 6e ...println
28. 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
...(Ljava/lang/String;)V
00 20 access_flags
00 05 this_class
00 06 super_class
00 00 interfaces_count
00 00 fields_count
00 02 methods_count
methods[2]:
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
0. 00 00 access_flags;
00 07 name_index; 看看constant_pool的第7項: <init> 表明當(dāng)前描述構(gòu)
造函數(shù)
00 08 descriptor_index;
00 01 attributes_count;
00 09 attribute_name_index 0x09 看看constant_pool的第9項,簡單明了Cod
e ?。?br> 00 00 00 1d attribute_length = 29
00 01 max_stack
00 01 max_locals
00 00 00 05 code_length
2a b7 00 01 b1 JVM定義的操作碼代碼段數(shù)組
00 00 exception_table_length
00 01 attributes_count 一個,接下來是attribute_info結(jié)構(gòu)
00 0a attribute_name_index 看看constant_pool的第10項: LineNumberTable(
顯然調(diào)試用)
00 00 00 06 attribute_length
00 01 line_number_table_length
00 00 start_pc
00 01 line_number
1. 00 09 access_flags PUBLIC & STATIC
00 0b name_index; 表明當(dāng)前描述main函數(shù)
00 0c descriptor_index; ...([Ljava/lang/String;)V
00 01 attributes_count;
00 09 attribute_name_index Code
00 00 00 25 attribute_length = 37
00 02 max_stack
00 01 max_locals
00 00 00 09 code_length
b2 00 02 12 03 b6 00 04 b1 代碼數(shù)組 codeArray1[0-8]
00 00 exception_table_length
00 01 attributes_count 接下來是attribute_info結(jié)構(gòu)
00 0a attribute_name_index LineNumberTable
00 00 00 0a attribute_length
00 02 line_number_table_length
00 00 start_pc
00 05 line_number
00 08 start_pc : codeArray1[8] = 0xb1 --> return
00 06 line_number 第6行源程序為 }
00 01 attributes_count
00 0d attribute_name_index 屬性為SourceFile
00 00 00 02 attribute_length
00 0e sourcefile_index constant_pool[0x0e] --- > "Test.java"
接下來我們看看main()函數(shù)對應(yīng)的代碼:
b2 00 02 12 03 b6 00 04 b1
0xb2 0x00 0x02 : getstatic #2
看看constant_pool[0x02] :09 00 10 00 11
0x09 : CONSTANT_Fieldref 0x10: class index 0x11 :nam
e-type-index
constant_pool[0x10]: --> constant_pool[0x17] : java/lang/System
constant_pool[0x11]: 0x18 : class index 0x19 :name-type-index
constant_pool[0x18] : out
constant_pool[0x19] : Ljava/io/PrintStream
即 System.out 為 java.io.PrintStream 類型
0x12 0x03 : ldc #3
看看 constant_pool[3] : 08 00 12 0x08 : CONSTANT_String 0x12 :
string_index
指向一個字符串 constant_pool[0x12]: "Hello World!"
故該指令加載了字符串索引到本地棧
0xb6 0x00 0x04: invokevirtual #4
------->到constant_pool查查 0x13 :class 0x14 :name-t
看看constant_pool[0x13]:java/io/
PrintStream
constant_pool[20] :--> 00 1b 00
1c
constant_pool[0x1b]:println
. . . . :(Ljava/lang/
String;)V
故該指令調(diào)用了 java.io.PrintStream.println(java.lang.String)
而參數(shù)則為 ldc #3 加載的 "Hello World!"
0xb1 : return