您的位置:首页技术文章
文章详情页

JVM之class文件结构

【字号: 日期:2024-07-20 09:02:50浏览:76作者:猪猪
内容: by cloud (safesuite@263.net ) 定义:u1 1个字节为单位的非负值 u2 2个字节为单位的非负值 u3 . . . . . . . . (其他以此类推 ) Java文件结构用类似struct的描述如下: ClassFile { u4 magic; // 必须为: 0xCAFEBABE u2 minor_version; u2 major_version; //CLASS文件结构主次版本号 JAVA2支持45.0-46.0 u2 constant_pool_count; //记录常量信息 cp_info constant_pool[constant_pool_count-1]; //计数从1开始 u2 access_flags; //class/interface访问权限 u2 this_class; //指向constant_poll中的有效索引值 u2 super_class; //0或指向constant_poll中的有效索引值,对于interface必须为非0 u2 interfaces_count; //superinterfaces的个数 u2 interfaces[interfaces_count]; //计数[0,count-1) 对应constant_pool中的一个索引值 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分别对应结构变化为 1. CONSTANT_Class CONSTANT_Class_info { u1 tag; u2 name_index; } 2. CONSTANT_Fieldref CONSTANT_Fieldref_info { u1 tag; u2 class_index; //constant_pool的索引,对应CONSTANT_Class_info u2 name_and_type_index;//constant_pool的索引,对应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则定义的是一个类而非接口。 如果设置了ACC_INTERFACE,那么ACC_ABSTRACT位也必须被设置,当然也可以设置ACC_PUBLIC。 ACC_SUPER用以表明invokespecial语义,Sun公司老的JAVA编译器没有设置ACC_SUPER,并且老的JVM 忽略ACC_SUPER位,但新的编译器应该实现invokespecial语义。 其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。 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; //访问控制权 u2 name_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。 u2 descriptor_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。 u2 attributes_count; attribute_info attributes[attributes_count]; //attribute_info将在mothods后描述。 } 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位,且不能置其他位。 其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。 methods指明了类中的所有方法。 method_info { u2 access_flags; u2 name_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info u2 descriptor_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info u2 attributes_count; attribute_info attributes[attributes_count]; //此处只能出现Code、Exceptions、Synthetic、Deprecated四种类型的属性 } access_flags访问权描述如下: 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中的索引,对应于CONSTANT_Utf8_info描述。 u4 attribute_length; u1 info[attribute_length]; } 现在已经预定义的属性有: 1. SourceFile : attribute_info被替代为: SourceFile_attribute { u2 attribute_name_index; u4 attribute_length; u2 sourcefile_index; //指向constant_pool中的一个CONSTANT_Utf8_info 结构。 } 2. ConstantValue : attribute_info被替代为: ConstantValue_attribute { u2 attribute_name_index; u4 attribute_length; //必须为2 u2 constantvalue_index; } 对于constantvalue_index意义如下: longCONSTANT_Long floatCONSTANT_Float double CONSTANT_Double int, short, char, byte, boolean CONSTANT_Integer String CONSTANT_String ConstantValue用于field_info 中,用于描述一个static常量, 且此时field_info的access_flags应为ACC_STATIC 3. Code : attribute_info被替代为: Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; //执行此函数时可用的栈的最大深度 u2 max_locals; //执行此函数可用到的最大本地变量数目,包括参数。 // 注意:一个long/double相当于2个变量数目. u4 code_length; //本函数用到的代码长度。 u1 code[code_length]; //实现本函数的真正字节码 u2 exception_table_length; { u2 start_pc; u2 end_pc; //捕获违例时执行代码数组中的[start_pc, end_pc)部分 u2 handler_pc; //现在还不大明白他是干嘛的!! u2 catch_type; //指向constant_pool的索引,对应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结构中。 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 中, 一个没有出现在源程序中的变量必须使用Synthetic标记。 7. LineNumberTable : attribute_info被替代为: 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]; } LineNumberTable用于Code属性中,通常用于调试。 8. LocalVariableTable : attribute_info被替代为: LocalVariableTable_attribute { u2 attribute_name_index; u4 attribute_length; u2 local_variable_table_length; { u2 start_pc; u2 length; //当解释到代码数组的[start_pc,start_pc+length] //时变量必须被赋值?? u2 name_index; u2 descriptor_index; u2 index; //到本地变量数组的一个索引 } local_variable_table[local_variable_table_length]; } 9. Deprecated : attribute_info被替代为: Deprecated_attribute { u2 attribute_name_index; u4 attribute_length; //必须为0 } 当然你也可以定义自己的属性,但要你自己的编译器和虚拟机实现。JVM将忽略自己不认可的属性。 来实践一下吧!编写一个最简单的程序: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 ........()01:03 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e V...Code...LineN01:04 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69 umberTable...mai01:05 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 n...([Ljava/lang01:06 2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75 /String;)V...Sou01:07 72 63 65 46 69 6c 65 01 00 09 54 65 73 74 2e 6a rceFile...Test.j>d02: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/Objec02:04 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 t...java/lang/Sy02:05 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 stem...out...Lja02:06 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 va/io/PrintStrea02:07 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 m;...java/io/Pri>d03:00 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e 74 ntStream...print03:01 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 ln...(Ljava/lang03: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 ................>d04: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 magic00 03 00 2d 次主版本号,换算一下: 45.3 (注意,不是高字节在前,别犯职业病!)00 1d constant_pool元素个数加一 : 29 那么constant_pool就是[1-28]constant_pool: 1-28 1. 0a 00 06 00 0f 0x0a :CONSTANT_InterfaceMethodref 0x06 :class index 0x0f :name-type-index2. 09 00 10 00 11 0x09 : CONSTANT_Fieldref 0x10: . . . 0x11 :. . . .3. 08 00 12 0x08 : CONSTANT_String 0x12 : string_index4. 0a 00 13 00 14 0x0a同于1.5. 07 00 15 0x07 : CONSTANT_Class 0x15 : name_index6. 07 00 167. 01 00 06 3c 69 6e 69 74 3e 01 ... 0x01 CONSTANT_Utf8 0x06 : string length '' : 构造函数8. 01 00 03 28 29 56 ...()V 函数,无参数 0x01 . . . . . . 0x03 : . . . . '()V' : .. .9. 01 00 04 43 6f 64 65 ...Code10. 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 ...LineNumberTable11. 01 00 04 6d 61 69 6e ...main12. 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 函数,参数为String[]类型13. 01 00 0a 53 6f 75 72 63 65 46 69 6c 65 ...SourceFile14. 01 00 09 54 65 73 74 2e 6a 61 76 61 ...Test.java15. 0c 00 07 00 08 0x0c:CONSTANT_NameAndType 07 : name-index 08:name-type-index16. 07 00 1717. 0c 00 18 00 1918. 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 ...Hello World!19. 07 00 1a20. 0c 00 1b 00 1c21. 01 00 04 54 65 73 74 ...Test22. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 ...java/lang/Object23. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d ...java/lang/System24. 01 00 03 6f 75 74 ...out25. 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/PrintStream27. 01 00 07 70 72 69 6e 74 6c 6e ...println28. 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_flags00 05 this_class00 06 super_class00 00 interfaces_count00 00 fields_count00 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项: 表明当前描述构造函数 00 08 descriptor_index; 00 01 attributes_count; 00 09 attribute_name_index 0x09 看看constant_pool的第9项,简单明了Code !! 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定义的操作码代码段数组 00 00 exception_table_length 00 01 attributes_count 一个,接下来是attribute_info结构 00 0a attribute_name_index 看看constant_pool的第10项: LineNumberTable(显然调试用) 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; 表明当前描述main函数 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 代码数组 codeArray1[0-8] 00 00 exception_table_length 00 01 attributes_count 接下来是attribute_info结构 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_count00 0d attribute_name_index 属性为SourceFile00 00 00 02 attribute_length00 0e sourcefile_index constant_pool[0x0e] ---> 'Test.java' 接下来我们看看main()函数对应的代码: 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 :name-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 故该指令调用了 java.io.PrintStream.println(java.lang.String) 而参数则为 ldc #3 加载的 'Hello World!'0xb1 : return Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd
相关文章: