JVM实探-class文件格式实战(3)

实战演练

先创建一个简单类

package com.weyne.demo.jvm;

public class Test {
    private static String a = "test-a";

    public static void main(String[] args) {
        System.out.println("Hello world");
    }
}

通过jclasslib可以看到结构体信息

通过Sublime等16进制文件编辑器查看Test.class字节码文件如下,该文件为16进制编码文件。

cafe babe 0000 0034 0029 0a00 0800 1909
001a 001b 0800 1c0a 001d 001e 0800 1f09
0007 0020 0700 2107 0022 0100 0161 0100
124c 6a61 7661 2f6c 616e 672f 5374 7269
6e67 3b01 0006 3c69 6e69 743e 0100 0328
2956 0100 0443 6f64 6501 000f 4c69 6e65
4e75 6d62 6572 5461 626c 6501 0012 4c6f
6361 6c56 6172 6961 626c 6554 6162 6c65
0100 0474 6869 7301 0019 4c63 6f6d 2f77
6579 6e65 2f64 656d 6f2f 6a76 6d2f 5465
7374 3b01 0004 6d61 696e 0100 1628 5b4c
6a61 7661 2f6c 616e 672f 5374 7269 6e67
3b29 5601 0004 6172 6773 0100 135b 4c6a
6176 612f 6c61 6e67 2f53 7472 696e 673b
0100 083c 636c 696e 6974 3e01 000a 536f
7572 6365 4669 6c65 0100 0954 6573 742e
6a61 7661 0c00 0b00 0c07 0023 0c00 2400
2501 000b 4865 6c6c 6f20 776f 726c 6407
0026 0c00 2700 2801 0006 7465 7374 2d61
0c00 0900 0a01 0017 636f 6d2f 7765 796e
652f 6465 6d6f 2f6a 766d 2f54 6573 7401
0010 6a61 7661 2f6c 616e 672f 4f62 6a65
6374 0100 106a 6176 612f 6c61 6e67 2f53
7973 7465 6d01 0003 6f75 7401 0015 4c6a
6176 612f 696f 2f50 7269 6e74 5374 7265
616d 3b01 0013 6a61 7661 2f69 6f2f 5072
696e 7453 7472 6561 6d01 0007 7072 696e
746c 6e01 0015 284c 6a61 7661 2f6c 616e
672f 5374 7269 6e67 3b29 5600 2100 0700
0800 0000 0100 0a00 0900 0a00 0000 0300
0100 0b00 0c00 0100 0d00 0000 2f00 0100
0100 0000 052a b700 01b1 0000 0002 000e
0000 0006 0001 0000 0003 000f 0000 000c
0001 0000 0005 0010 0011 0000 0009 0012
0013 0001 000d 0000 0037 0002 0001 0000
0009 b200 0212 03b6 0004 b100 0000 0200
0e00 0000 0a00 0200 0000 0700 0800 0800
0f00 0000 0c00 0100 0000 0900 1400 1500
0000 0800 1600 0c00 0100 0d00 0000 1e00
0100 0000 0000 0612 05b3 0006 b100 0000
0100 0e00 0000 0600 0100 0000 0400 0100
1700 0000 0200 18

magic:u4-四字节,cafe babe,固定不变

minor_version:u2 0000 

major_version:u2 0034(16)转10进制,3*16+4=52,对应JDK1.8

constant_pool_count:u2 0029,转10进制,2*16+9=41,表示常量池成员数为constant_pool_count-1=40个。

第一个常量池成员先根据u1(第一个字节)判断类型,0a(16)->10(10)是CONSTANT_Methodref类型,对应的结构为

{
    u1 tag 0a  10对应CONSTANT_Methodref_info
    u2 class_index 00 08 java/lang/Object
    u2 name_and_type_index 00 19  25  #11+#12=<init>:()V
}

剩余的常量池成员不一一解析了,直接贴出来

constant_pool[
1	## 0a 00 08 00 19
	u1 tag 0a  10对应CONSTANT_Methodref_info
	u2 class_index 00 08 java/lang/Object
	u2 name_and_type_index 00 19  25  #11+#12=<init>:()V

2	## 09 00 1a 00 1b
	u1 tag 09  9对应CONSTANT_Fieldref_info 
	u2 class_index 00 1a java/lang/Object  java/lang/System
	u2 name_and_type_index 00 1b  25  #36+#37=out + Ljava/io/PrintStream

3	## 08 00 1c
	u1 tag 08  8对应CONSTANT_String_info 
	u2 class_index 00 1c 28 Hello world

4	## 0a 00 1d 00 1e
	u1 tag 0a  10对应CONSTANT_Methodref_info
	u2 class_index 00 1d java/io/PrintStream
	u2 name_and_type_index 00 1e  println

5	## 08 00 1f
	u1 tag 08  8对应CONSTANT_String_info 
	u2 class_index 00 1f test-a

6	## 09 00 07 00 20
	u1 tag 09  9对应CONSTANT_Fieldref_info 
	u2 class_index 00 07 com/weyne/demo/jvm/Test
	u2 name_and_type_index 00 20  #9+#10=a + Ljava/lang/String;

7	## 07 00 21
	u1 tag 07  7对应CONSTANT_Class_info 
	u2 index 00 21 com/weyne/demo/jvm/Test

8	## 07 00 22
	u1 tag 07 7对应CONSTANT_Class_info 
	u2 index 00 22 java/lang/Object

9	## 01 00 01 61
	u1 tag 01 CONSTANT_utf8_info   
	u2 00 01对应utf编码长度
	u1 index 61 a

10	## 01 00 12
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 12 18对应utf编码长度
	u1 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 长度为length的utf-8编码的字符串 Ljava/lang/String;

11	## 01 00 06 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 06 6对应utf编码长度
	u1 3c 69 6e 69 74 3e 长度为length的utf-8编码的字符串 <init>

12	##01 00 03 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 03 3对应utf编码长度
	u1 28 29 56 长度为length的utf-8编码的字符串 ()V

13	##01 00 04 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 04 对应utf编码长度
	u1 43 6f 64 65 长度为length的utf-8编码的字符串 Code

14	##01 00 0f 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 0f 15对应utf编码长度
	u1 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 长度为length的utf-8编码的字符串 LineNumberTable

15	##01 00 12 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 12 18对应utf编码长度
	u1 4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 长度为length的utf-8编码的字符串 LocalVariableTable

16	##01 00 04 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 04 18对应utf编码长度
	u1 74 68 69 73 长度为length的utf-8编码的字符串 this

17	##01 00 19 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 19 25对应utf编码长度
	u1 4c63 6f6d 2f77 6579 6e65 2f64 656d 6f2f 6a76 6d2f 5465 7374 3b 长度为length的utf-8编码的字符串 Lcom/weyne/demo/jvm/Test;

18	##01 00 04 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 04 4对应utf编码长度
	u1 6d 61 69 6e 长度为length的utf-8编码的字符串 main

19	##01 00 16 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 04 4对应utf编码长度
	u1 28 5b4c 6a61 7661 2f6c 616e 672f 5374 7269 6e67 3b29 56 长度为length的utf-8编码的字符串 ([Ljava/lang/String;)V

20	##01 00 04 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 04 4对应utf编码长度
	u1 61 72 67 73 长度为length的utf-8编码的字符串 args

21	##01 00 13 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 13 19对应utf编码长度
	u1 5b 4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b 长度为length的utf-8编码的字符串 [Ljava/lang/String;

22	##01 00 08 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 08 8对应utf编码长度
	u1 3c 636c 696e 6974 3e 长度为length的utf-8编码的字符串 <clinit>

23	##01 00 0a 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 0a 10对应utf编码长度
	u1 536f 7572 6365 4669 6c65 长度为length的utf-8编码的字符串 SourceFile

24	##01 00 09
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 09 9对应utf编码长度
	u1 54 6573 742e 6a61 7661 长度为length的utf-8编码的字符串 Test.java

25	##0c 
	u1 tag 0c  12 CONSTANT_NameAndType_info 
	u2 00 0b 11指向该字段或方法名称常量项的索引 <init> 
	u2 00 0c 12指向该字段或方法描述符常量项的索引 ()V

26	##07 
	u1 tag 07  CONSTANT_Class_info 
	u2 00 23 11指向全限定名常量项的索引 java/lang/System

27	##0c 
	u1 tag 0c  12 CONSTANT_NameAndType_info 
	u2 00 24 指向该字段或方法名称常量项的索引 out
	u2 00 25 指向该字段或方法描述符常量项的索引 Ljava/io/PrintStream

28	##01  
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 0a 对应utf编码长度
	u1 48 65 6c 6c 6f 20 77 6f 72 64 长度为length的utf-8编码的字符串 Hello word

29	##07 
	u1 tag 07  CONSTANT_Class_info 
	u2 00 26 指向全限定名常量项的索引 java/io/PrintStream

30	##0c 
	u1 tag 0c  12 CONSTANT_NameAndType_info 
	u2 00 27 指向该字段或方法名称常量项的索引 println
	u2 00 28 指向该字段或方法描述符常量项的索引 (Ljava/lang/String;)V

31	##01
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 06 对应utf编码长度
	u2 74 65 73 74 2d 61 长度为length的utf-8编码的字符串  test-a

32	##0c 
	u1 tag 0c  12 CONSTANT_NameAndType_info 
	u2 00 09 指向该字段或方法名称常量项的索引 a
	u2 00 0a 指向该字段或方法描述符常量项的索引 Ljava/lang/String;

33	##01
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 17 23对应utf编码长度
	u2 63 6f6d 2f77 6579 6e65 2f64 656d 6f2f 6a76 6d2f 5465 7374 长度为length的utf-8编码的字符串  com/weyne/demo/jvm/Test

34	##01
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 10 对应utf编码长度
	u2 6a 6176 612f 6c61 6e67 2f4f 626a 6563 74 长度为length的utf-8编码的字符串  java/lang/Object

35	##01 0010 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 10 对应utf编码长度
	u2 6a61 7661 2f6c 616e 672f 5379 7374 656d 长度为length的utf-8编码的字符串  java/lang/System

36	##01
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 03 对应utf编码长度
	u2 6f 7574 长度为length的utf-8编码的字符串  out

37	##01 
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 15 21对应utf编码长度
	u2 4c 6a61 7661 2f69 6f2f 5072 696e 7453 7472 6561 6d3b 长度为length的utf-8编码的字符串 Ljava/io/PrintStream;

38	##01
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 13 对应utf编码长度
	u2 6a 6176 612f 696f 2f50 7269 6e74 5374 7265 616d 长度为length的utf-8编码的字符串 java/io/PrintStream


39	##01
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 07 对应utf编码长度
	u2 70 7269 6e74 6c6e 长度为length的utf-8编码的字符串 println

40	##01
	u1 tag 01  CONSTANT_utf8_info 
	u2 00 15 对应utf编码长度21
	u2 28 4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b 2956 长度为length的utf-8编码的字符串 (Ljava/lang/String;)V
}

Access_flags u2-> 00 21  = 0x0020|0x0001 = ACC_SUPER | ACC_PUBLIC

this_class u2->00 07 CONSTANT_Class_info #07-> #33 com/weyne/demo/jvm/Test

super_class u2-> 00 08 CONSTANT_Class_info #08->#34 java/lang/Object

interface_count u2-> 00 00 

interface 空,count为0

fields_count u2-> 00 01
    fields_info [
        u2 access_flags 00 0a 0x0002|0x0008  ACC_PRIVATE | ACC_STATIC
        u2 name_index 字段的名称 00 09 a
        u2 descriptor_index 字段的描述符 00 0a Ljava/lang/String;
        u2 attributes_count 0000
        attribute_info
   ]

余下的直接贴上

u2 method_count 00 03
 	method_info1[
 		u2 access_flags 0001 0x0001  ACC_PUBLIC
		u2 name_index 00 0b <init>
		u2 descriptor_index 00 0c ()V
		u2 attributes_count 00 01
		attribute_info{
			u2 attribute_name_index 00 0d Code
			{

				Code_attribute {
				    u2 attribute_name_index  0000 
				    u4 attribute_length 002f 
				    	0001 0001 0000 0005 2ab7 0001 b100 0000 02 00 0e00 0000 06 00 01 00 0000 0300 0f00 0000 0c00 0100 0000 0500 1000 1100 00
				    u2 max_stack 0001
				    u2 max_locals 0001
				    u4 code_length 0000 0005
				    u1 code[code_length] 2a b7 00 01 b1
				    u2 exception_table_length 00 00
				    { 
				        u2 start_pc; 
				        u2 end_pc; 
				        u2 handler_pc; 
				        u2 catch_type; 
				    } exception_table[exception_table_length]; 
				    u2 attributes_count 00 02
				    	LineNumberTable_attribute {
						    u2 attribute_name_index  00 0e 14
						    u4 attribute_length 00 00 00 06
						    u2 line_number_table_length 00 01
						    { 
						        u2 start_pc 00 00
						        u2 line_number 00 03 
						    } line_number_table[line_number_table_length]; 
						}
				    	LocalVariable_attribute 00 0f{
						    u2 attribute_name_index  
						    u4 attribute_length 00 00 00 0c  
						    u2 local_variable_table_length 00 01
							    {   u2 start_pc 00 00
							        u2 length 00 05
							        u2 name_index 00 10  this
							        u2 descriptor_index 00 11 Lcom/weyne/demo/jvm/Test;
							        u2 index 00 00
							    } local_variable_table[local_variable_table_length];
						}
				}
			}

		}
 	]

 	method_info2[
 		u2 access_flags 00 09 0x0001|0x0008  ACC_PUBLIC | ACC_STATIC
		u2 name_index 00 12 main
		u2 descriptor_index 00 13 ([Ljava/lang/String;)V
		u2 attributes_count 00 01
		attribute_info{
			u2 attribute_name_index 00 0d Code
			{

				Code_attribute {
				    u2 attribute_name_index  0000 
				    u4 attribute_length 00 37 
				    	00 0200 0100 0000
						09b2 0002 1203 b600 04b1 0000 0002 000e
						0000 000a 0002 0000 0007 0008 0008 000f
						0000 000c 0001 0000 0009 0014 0015 0000
				    u2 max_stack 00 02
				    u2 max_locals 0001
				    u4 code_length 00 0000 09
				    u1 code[code_length] b2 0002 1203 b600 04b1
				    u2 exception_table_length 00 00
				    { 
				        u2 start_pc; 
				        u2 end_pc; 
				        u2 handler_pc; 
				        u2 catch_type; 
				    } exception_table[exception_table_length]; 
				    u2 attributes_count 00 02
			    	LineNumberTable_attribute {
					    u2 attribute_name_index  00 0e 14
					    u4 attribute_length 00 00 00 0a
					    u2 line_number_table_length 00 02
					    [
						    { 
						        u2 start_pc 00 00
						        u2 line_number 00 07
						    } line_number_table[line_number_table_length]; 
						    { 
						        u2 start_pc 0008 
						        u2 line_number 0008
						    } line_number_table[line_number_table_length]; 
					    ]
					}
			    	LocalVariable_attribute 00 0f{
					    u2 attribute_name_index  
					    u4 attribute_length 00 00 00 0c  
					    u2 local_variable_table_length 00 01
						    {   
						    	u2 start_pc 00 00
						        u2 length 00 09
						        u2 name_index 00 14  args
						        u2 descriptor_index 00 15 [Ljava/lang/String;
						        u2 index 00 00
						    } local_variable_table[local_variable_table_length];
					}
				}
			}
		}
 	]

 	method_info3[
 		u2 access_flags 0008 0x0008  ACC_STATIC
		u2 name_index 00 16 <clinit>
		u2 descriptor_index 00 0c ()V
		u2 attributes_count 00 01
		attribute_info{
			u2 attribute_name_index 00 0d Code
			{

				Code_attribute {
				    u2 attribute_name_index  0000 001e 
				    u4 attribute_length 00 1e
				    	0001
						0000 0000 0006 1205 b300 06b1 0000 0001
						000e 0000 0006 0001 0000 0004
				    u2 max_stack 0001
				    u2 max_locals 0000
				    u4 code_length 0000 0006
				    u1 code[code_length] 1205 b300 06b1
				    u2 exception_table_length 00 00
				    { 
				        u2 start_pc; 
				        u2 end_pc; 
				        u2 handler_pc; 
				        u2 catch_type; 
				    } exception_table[exception_table_length]; 
				    u2 attributes_count 0001
			    	LineNumberTable_attribute {
					    u2 attribute_name_index  00 0e 14
					    u4 attribute_length 0000 0006
					    u2 line_number_table_length 0001
					    [
						    { 
						        u2 start_pc 00 00
						        u2 line_number 0004
						    } line_number_table[line_number_table_length]; 
					    ]
					}
				}
			}
		}
 	]

u2 attributes_count 0001
SourceFile_attribute { 
    u2 attribute_name_index  0017  SourceFile
    u4 attribute_length 0000 0002 
    u2 sourcefile_index 0018 Test.java
} 	

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值