0.从0开始的手写java虚拟机-class文件示例解读
前言:
笔者最近在阅读《手写 Java 虚拟机》,在实践过程中也遇到了诸多疑问,所谓书山有路勤为径,因而希望能够将我的阅读心得记录下来,供同好互相交流;
以下是一个非常简单明了的 class 文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
public class ClassFileTest {
public static final boolean FLAG = false;
public static final byte BYTE = 123;
public static final char X = 'X';
public static final short SHORT = 12345;
public static final int INT = 123456789;
public static final long LONG = 1234567L;
public static final float PI = 3.1415925F;
public static final double E = 2.71828D;
public ClassFileTest() {
}
public static void main(String[] args) {
System.out.println("HelloWorld");
}
}
其 16 进制文件对应为
CA FE BA BE 00 00 00 3A 00 3D 0A 00 02 00 03 07 00 04 0C 00 05 00 06 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 09 00 08 00 09 07 00 0A 0C 00 0B 00 0C 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 08 00 0E 01 00 0A 48 65 6C 6C 6F 57 6F 72 6C 64 0A 00 10 00 11 07 00 12 0C 00 13 00 14 01 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 07 00 16 01 00 0D 43 6C 61 73 73 46 69 6C 65 54 65 73 74 01 00 04 46 4C 41 47 01 00 01 5A 01 00 0D 43 6F 6E 73 74 61 6E 74 56 61 6C 75 65 03 00 00 00 00 01 00 04 42 59 54 45 01 00 01 42 03 00 00 00 7B 01 00 01 58 01 00 01 43 03 00 00 00 58 01 00 05 53 48 4F 52 54 01 00 01 53 03 00 00 30 39 01 00 03 49 4E 54 01 00 01 49 03 07 5B CD 15 01 00 04 4C 4F 4E 47 01 00 01 4A 05 00 00 00 00 00 12 D6 87 01 00 02 50 49 01 00 01 46 04 40 49 0F DA 01 00 01 45 01 00 01 44 06 40 05 BF 09 95 AA F7 90 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 01 00 04 74 68 69 73 01 00 0F 4C 43 6C 61 73 73 46 69 6C 65 54 65 73 74 3B 01 00 04 6D 61 69 6E 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 01 00 04 61 72 67 73 01 00 13 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 01 00 0A 53 6F 75 72 63 65 46 69 6C 65 01 00 12 43 6C 61 73 73 46 69 6C 65 54 65 73 74 2E 6A 61 76 61 00 21 00 15 00 02 00 00 00 08 00 19 00 17 00 18 00 01 00 19 00 00 00 02 00 1A 00 19 00 1B 00 1C 00 01 00 19 00 00 00 02 00 1D 00 19 00 1E 00 1F 00 01 00 19 00 00 00 02 00 20 00 19 00 21 00 22 00 01 00 19 00 00 00 02 00 23 00 19 00 24 00 25 00 01 00 19 00 00 00 02 00 26 00 19 00 27 00 28 00 01 00 19 00 00 00 02 00 29 00 19 00 2B 00 2C 00 01 00 19 00 00 00 02 00 2D 00 19 00 2E 00 2F 00 01 00 19 00 00 00 02 00 30 00 02 00 01 00 05 00 06 00 01 00 32 00 00 00 2F 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 02 00 33 00 00 00 06 00 01 00 00 00 01 00 34 00 00 00 0C 00 01 00 00 00 05 00 35 00 36 00 00 00 09 00 37 00 38 00 01 00 32 00 00 00 37 00 02 00 01 00 00 00 09 B2 00 07 12 0D B6 00 0F B1 00 00 00 02 00 33 00 00 00 0A 00 02 00 00 00 0D 00 08 00 0E 00 34 00 00 00 0C 00 01 00 00 00 09 00 39 00 3A 00 00 00 01 00 3B 00 00 00 02 00 3C
首先,通过查阅JVM 官方文档第 4 章,笔者了解到了 class 文件的基本格式
ClassFile {
(1)u4 magic;
(2)u2 minor_version;
(3)u2 major_version;
(4)u2 constant_pool_count;
(5)cp_info constant_pool[constant_pool_count-1];
(6)u2 access_flags;
(7)u2 this_class;
(8)u2 super_class;
(9)u2 interfaces_count;
(10)u2 interfaces[interfaces_count];
(11)u2 fields_count;
(12)field_info fields[fields_count];
(13)u2 methods_count;
(14)method_info methods[methods_count];
(15)u2 attributes_count;
(16)attribute_info attributes[attributes_count];
}
为避免叙述的混乱,因此我在每一个字段前加上了一个序号
u4 => 无符号 4 字节|
u2 => 无符号 2 字节
其他以此类推;
CA FE BA BE ((1)magic)
00 00 ((2)minor_version:0)
00 3A ((3)major_version:0x3A(58))
00 3D ((4)constant_pool_count: 61)
(5)cp_info[constant_pool_count]
(ps:字符串常量池的大小等于constant_pool中实际大小+1,且id从1开始,且long和double占2格)
cp_info{u1 tag; u1 info[]}
此处info详情如下:
cp_info常量池分类如下表:
tag | name | struct |
---|---|---|
1 | CONSTANT_Utf8 | {u1 tag; u2 length; u1 bytes[length]} |
3 | CONSTANT_Integer | {u1 tag; u4 bytes;} |
4 | CONSTANT_Float | {u1 tag; u4 bytes;} |
5 | CONSTANT_Long | {u1 tag; u4 high_bytes; u4 low_bytes;} |
6 | CONSTANT_Double | {u1 tag; u4 high_bytes; u4 low_bytes;} |
7 | CONSTANT_Class | {u1 tag; u2 name_index;} |
8 | CONSTANT_String | {u1 tag; u2 string_index;} |
9 | CONSTANT_Fieldref | {u1 tag; u2 class_Index; u2 name_and_type_index;} |
10 | CONSTANT_Methodref | {u1 tag; u2 class_index; u2 name_and_type_index;} |
11 | CONSTANT_InterfaceMethodref | {u1 tag; u2 class_index; u2 name_and_type_index;} |
12 | CONSTANT_NameAndType | {u1 tag; u2 name_index; u2 descriptor_index;} |
15 | CONSTANT_MethodHandle | {u1 tag; u2 reference_kind; u2 reference_index;} |
16 | CONSTANT_MethodType | {u1 tag; u2 descriptor_index;} |
17 | CONSTANT_Dynamic | {u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index;} |
18 | CONSTANT_invokedynamic | {u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index;} |
19 | CONSTANT_Module | {u1 tag; u2 name_index;} |
20 | CONSTANT_Package | {u1 tag; u2 name_index;} |
(1)(tag:10) 0A
(class_index:02) 00 02
(name_and_type_index:03) 00 03
(2)(tag:07) 07
(name_index:04) 00 04
(3)(tag:12) 0C
(name_index:05) 00 05
(descriptor_index:06;) 00 06
(4)(tag:01) 01
(length:16) 00 10
(bytes[length]:java/lang/Object) 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74
(5)(tag:01) 01
(length:06) 00 06
(bytes[length]:) 3C 69 6E 69 74 3E
//以下省略tag名称
(6) 01
(length:03) 00 03
(bytes[length]:()V) 28 29 56
(7)09
(class_index:08) 00 08
(name_and_type_index:09) 00 09
(8)07
(class_index:10) 00 0A
(9)0C
(name_index:11) 00 0B
(descriptor_index:12) 00 0C
(10)01
(length:10) 00 10
(bytes[length]:java/lang/System) 6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D
(11)01
(length:03) 00 03
(bytes[length]:out) 6F 75 74
(12)01
(length:21) 00 15
(bytes[length]:Ljava/io/PrintStream;) 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B
(13)08
(string_index:14) 00 0E
(14)01
(length:10) 00 0A
(bytes[length]:HelloWorld) 48 65 6C 6C 6F 57 6F 72 6C 64
(15)0A
(class_index:16) 00 10
(name_and_type_index:17) 00 11
(16)07
(name_index:18) 00 12
(17)0C
(name_index:19) 00 13
(descriptor_index:20) 00 14
(18)01
(legth:19) 00 13
(bytes[length]:java/io/PrintStream) 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D
(19)01
(length:07) 00 07
(bytes[length]:println) 70 72 69 6E 74 6C 6E
(20)01
(length:21) 00 15
(bytes[length]:(Ljava/lang/String;)V) 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56
(21)07
(name_index:22) 00 16
(22)01
(length:13) 00 0D
(bytes[length]:ClassFileTest) 43 6C 61 73 73 46 69 6C 65 54 65 73 74
(23)01
(length:04) 00 04
(bytes[length]:FLAG) 46 4C 41 47
(24)01
(length:01) 00 01
(bytes[length:Z]) 5A
(25)01
(length:13) 00 0D
(bytes[length]:ConstantValue) 43 6F 6E 73 74 61 6E 74 56 61 6C 75 65
(26)03
(Integer:0) 00 00 00 00
(27)01
(length:04) 00 04
(bytes[length]:BYTE) 42 59 54 45
(28)01
(length:01) 00 01
(bytes[length]:B) 42
(29)03
(Integer:123) 00 00 00 7B
(30)01
(length:01) 00 01
(bytes[length]:X) 58
(31)01
(length:01) 00 01
(bytes[length]:C) 43
(32)03
(Integer:88) 00 00 00 58
(33)01
(length:05) 00 05
(bytes[length]:SHORT) 53 48 4F 52 54
(34)01
(length:01) 00 01
(bytes[length]:S) 53
(35)03
(Integer:12345) 00 00 30 39
(36)01
(length:03) 00 03
(bytes[length]:INT) 49 4E 54
(37)01
(length:01) 00 01
**(bytes[length]:I)49
(38)03
(Integer:123456789) 07 5B CD 15
(39)01
(length:04) 00 04
(bytes[length]:LONG) 4C 4F 4E 47
(40)01
(length:01) 00 01
(bytes[length]:J) 4A
(41)05
(Long:1234567)
(high_bytes:0x00000000) 00 00 00 00
(low_bytes) 00 12 D6 87
(ps:Long和double占2个位置)
(43)01
(length:02) 00 02
(bytes[length]:PI) 50 49
(44)01
(length:01) 00 01
(bytes[length]:F) 46
(45)04
(Float(IEEE754):3.1415925) 40 49 0F DA
(46)01
(length:01) 00 01
(bytes[length]:E) 45
(47)01
(length:01)) 00 01
(bytes[length]????) 44
(48)06
(Double:2.71828)
(high_bytes) 40 05 BF 09
(low_bytes) 95 AA F7 90
(50)01
(length:04) 00 04
(bytes[length]:Code) 43 6F 64 65
(51)01
(length:15) 00 0F
(bytes[length]:LineNumberTable) 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65
(52)01
(length:18) 00 12
(bytes[length]:LocalVariableTable) 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65
(53)01
(length:04) 00 04
(bytes[length]:this) 74 68 69 73
(54)01
(length:15) 00 0F
(bytes[length]:LClassFileTest;) 4C 43 6C 61 73 73 46 69 6C 65 54 65 73 74 3B
(55)01
(length:04) 00 04
(bytes[length]:main) 6D 61 69 6E
(56)01
(length:22) 00 16
(bytes[length]:([Ljava/lang/String;)V) 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56
(57)01
(length:4) 00 04
(bytes[length]:args) 61 72 67 73
(58)01
(length:19) 00 13
(bytes[length][Ljava/lang/String;) 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B
(59)01
(length:10) 00 0A
(bytes[length]:SourceFile) 53 6F 75 72 63 65 46 69 6C 65
(60)01
(length:12) 00 12
(bytes[length]:ClassFIleTest.java) 43 6C 61 73 73 46 69 6C 65 54 65 73 74 2E 6A 61 76 61
自此,class文件常量池已分析完毕。
(6)access_flag
flag name | value |
---|---|
ACC_PUBLIC | 0x0001 |
ACC_PRIVATE | 0x0002 |
ACC_PROTECTED | 0x0004 |
ACC_STATIC | 0x0008 |
ACC_FINAL | 0x0010 |
ACC_VOLATILE | 0x0040 |
ACC_TRANSIENT | 0x0080 |
ACC_SYNTHETIC | 0x1000 |
ACC_ENUM | 0x4000 |
ACC_SUPER | 0x0020 |
ACC_INTERFACE | 0x0200 |
ACC_ABSTRACT | 0x0400 |
ACC_ANNOTATION | 0x2000 |
ACC_MODULE | 0x8000 |
(0x0001(ACC_PUBLIC) + 0x0020(ACC_SUPER)) 00 21
(7)(常量池索引)this_class(=>21)ClassFileTest 00 15
(8)(常量池索引)super_class(=>02)java/lang/Object 00 02
(9)interface_count:0 00 00
(10)interfaces[interface_count]
//以下开始字段的描述
(11)fields_count 00 08 (一共8个字段)
(12)fields[fields_count]
field_info{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
attribute_info{
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
//对于descriptor(描述符)
fieldTypeItem | Type |
---|---|
B | byte |
C | char |
D | double |
F | float |
I | int |
J | long |
L<Classname>; | reference |
S | short |
Z | boolean |
[ | one array dimension reference |
以下涉及到attribute;
ConstantValue_attribute{
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
一共8个字段
(1)
(access_flags:0x0001(ACC_PUBLIC)+0x0010(ACC_Final)+0x0008(ACC_STATIC)) 00 19
(name_index:23=>FLAG) 00 17
(descriptor_index:24=>Z) 00 18
(attribute_count:1) 00 01
(attribute_name_index:25=>ConstantValue) 00 19
Constantvalue_attribute->
(attribute_length:02) 00 00 00 02
(constanvalue_index:2->0) 00 1A
(2)
(access_flags:public static final) 00 19
(name_index:27->BYTE) 00 1B
(descriptor_index:28->B) 00 1C
(attributes_count:1) 00 01
(attribute_name_index:25->ConstantValue) 00 19
Constantvalue_attribute->
(attribute_length:02) 00 00 00 02
(constantvalue_index:29->123) 00 1D
(3)
(access_flags:public static final) 00 19
(name_index:30->X) 00 1E
(descriptor_index:31->C) 00 1F
(attributes_count:01) 00 01
(attribute_name_index:25->ConstantValue) 00 19
Constantvalue_attribute->
(attribute_length:02) 00 00 00 02
(constantvalue_index:32->88(‘C’)) 00 20
(4)
(access_flags:public static final) 00 19
(name_index:33->SHORT) 00 21
(descriptor_index:34) 00 22
(attributes_count:01) 00 01
(attribute_name_index:25->ConstantValue) 00 19
Constantvalue_attribute->
(attribute_length:02) 00 00 00 02
(constantvalue_index:35->12345) 00 23
(5)
(access_flags:public static final) 00 19
(name_index:36->INT) 00 24
(descriptor_index:37->I) 00 25
(attributes_count:01) 00 01
ConstantValue_attribute->
(attribute_name_index:25->ConstantValue) 00 19
(attribute_length:02) 00 00 00 02
(constantvalue_index:38->123456789;) 00 26
(6)
(access_flags:public static final) 00 19
(name_index:39->LONG) 00 27
(descriptor_index:40->J) 00 28
(attributes_count:01) 00 01
(attribute_name_index:25->ConstantValue) 00 19
ConstantValueAttribute->
(attribute_length:02) 00 00 00 02
(constantvalue_index:41->1234567) 00 29
(7)
(access_flags:public static final) 00 19
(name_index:43->PI) 00 2B
(descriptor_index:44->F) 00 2C
(attributes_count:01) 00 01
(attribute_name_index:25->ConstantValue) 00 19
ConstantValue_attribute->
(attribute_length:02) 00 00 00 02
(constantValue_index:45->3.1415925) 00 2D
(8)
(access_flags:public static final) 00 19
(name_index:46->E) 00 2E
(descriptor_index:47->D) 00 2F
(attributes_count:01) 00 01
(attribute_name_index:25->ConstantValue) 00 19
ConstantValue_attribute->
(attribute_length:02) 00 00 00 02
(constantvalue_index:48->2.71828;) 00 30
以下要开始方法的描述了
method_info{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
attribute_info attributes[attributes_count];
}
Code_attribute{
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{
u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
}exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
(12)methods_count: 00 02
(13)methods[methods_count]
(1)
(access_flags:public) 00 01
(name_index:05->) 00 05
(descriptor_index:06->()V) 00 06
(attributes_count:01) 00 01
(attribute_name_index:50->Code) 00 32
(attribute_length:47) 00 00 00 2F
(max_stacks:01) 00 01
(max_lcoals:01) 00 01
(code_length:05) 00 00 00 05
以下设计到jvm指令集具体请查阅官网此处仅给出部分:
id | value | format |
---|---|---|
0x2A | aload_0 | |
0xB7 | invokespecial | |
0xB1 | return | invokespecial indexbyte1 indexbyte2 |
(code:)
2A
B7 00 01
B1
aload_0
invokespecial 01
return
(exception_table_length:0) 00 00
(attributes_count:02) 00 02
(attribute_name_index:51->LineNumberTable) 00 33
LineNumberTable_attribute{
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{
u2 start_pc;
u2 line_number;
}line_number_table[line_number_table_length];
}
(attribute_length:06) 00 00 00 06
(line_number_table_length:01) 00 01
(start_pc:0) 00 00
(end_pc:01) 00 01
(attribue_name_index:52->LocalVariableTable) 00 34
(attribute_length:12) 00 00 00 0C
(local_variable_table_length:01) 00 01
(start_pc:0;) 00 00
(length:05) 00 05
(name_index:53->this) 00 35
(descriptor_index:54->LClassFileTest;) 00 36
(index:0;) 00 00
(2)
(access_flags:public static) 00 09
(name_index:55->main) 00 37
(descriptor_index:56->(Ljava/lang/String;)V) 00 38
(attributes_count:01) 00 01
(attribute_name_index:50->Code) 00 32
(attribute_length:55;) 00 00 00 37
(max_stacks:02) 00 02
(max_locals:01) 00 01
(code_length:09) 00 00 00 09
id | value | format |
---|---|---|
0xB2 | getstatic | getstatic indexbyte1 indexbyte2 |
0x12 | ldc | ldc index |
0xB6 | invokevirtual | invokevirtual indexbyte1 indexbyte2 |
0xB1 | return |
B2 00 07
12 0D
B6 00 0F
B1
getstatic 07
ldc 13
invokevirtual 15
return
(exception_table_length:0) 00 00
(attributes_count:02;) 00 02
(attribute_name_index:51->LineNumberTable) 00 33
(attribute_length:10) 00 00 00 0A
(line_number_table_length:02) 00 02
(start_pc:0) 00 00
(line_number:13) 00 0D
(start_pc:8) 00 08
(end_pc:14) 00 0E
(attribute_name_index:52->LocalVariableTable) 00 34
(attribute_length:12) 00 00 00 0C
(local_variable_table_length:01) 00 01
(start_pc:0) 00 00
(length:09) 00 09
(name_index:57->args) 00 39
(descriptor_index:58->Ljava/lang/String;) 00 3A
(index:0) 00 00
14.attributes_count: 00 01
(attribute_name_index:59->SourceFile) 00 3B
SourceFile_attribute{
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index;
}
(attribute_length:02) 00 00 00 02
(sourcefile_index:60->ClassFileTest.java) 00 3C
本文地址:https://blog.csdn.net/Yuan_xii/article/details/113915929
上一篇: Java 启动加载器解析
下一篇: 黄权明明德才兼备,为什么没能得到重用?