python字节码解析_Java8虚拟机规范——Class字节码文件格式&样例解析

Jdk动态代理,CGlib动态代理都是通过生成字节码流并加载到Jvm中来实现生成代理类的。接下来介绍class文件的格式,希望能让大家对class字节码文件的认识更深入。

Class文件是一组以8位字节为基础单位的2进制流,各个数据项按顺序紧凑的排列在文件中,Class文件采用类似C语言的结构体的伪结构表示,在这种结构体中有两种数据类型,无符号数和表(table),无符号数属于基本数据类型u1、u2和u4类型分别代表占用1个字节、2个字节和4个字节的无符号数,无符号数可以用来描述数字、索引引用、数量或者按照UTF-8编码构成的字符串值(在Java中可以通过DataInput接口的readUnsignedByte、readUnsignedShort和readInt方法读取指定相应字节量的数据)。表类型(table)是由多个无符号数或其他表(table)作为数据项构成的嵌套结构,表结构类型通常以"_info"结尾。

Class文件伪结构表示:

ClassFile {    // 4字节的数据,称为魔数,十六进制表示为:0xCAFEBABE,用来标识这是一个Java字节码文件    u4             magic;    // 2字节,代表jdk小版本号    u2             minor_version;    // 2字节,代表jdk主版本号,主要用来判断当前jdk是否能兼容当前Class文件    u2             major_version;    // 2字节,代表常量池中数据项的个数    u2             constant_pool_count;  // table类型,数据项个数为constant_pool_count-1,数据项索引从1-constant_pool_count-1,索引0保留    cp_info {    u1 tag;    u1 info[];}        constant_pool[constant_pool_count-1];    u2             access_flags;// 2字节,访问标志    u2             this_class;// 2字节    u2             super_class;// 2字节    u2             interfaces_count;// 2字节    u2             interfaces[interfaces_count];// 2字节    u2             fields_count;// 2字节    field_info     fields[fields_count];//     u2             methods_count;// 2字节    method_info    methods[methods_count];//     u2             attributes_count;// 2字节    attribute_info attributes[attributes_count];// }

常量池constant_pool中的常量类型及类型结构如下(tag值以注释形式标出了,解析时需要用到)

// 每种常量类型的具体数据个数如下CONSTANT_Class_info {    u1 tag; // 7    u2 name_index;}CONSTANT_Fieldref_info {    u1 tag; // 9    u2 class_index;    u2 name_and_type_index;}CONSTANT_Methodref_info {    u1 tag; // 10    u2 class_index;    u2 name_and_type_index;}CONSTANT_InterfaceMethodref_info {    u1 tag; // 11    u2 class_index;    u2 name_and_type_index;}CONSTANT_String_info {    u1 tag; // 8    u2 string_index;}CONSTANT_Integer_info {    u1 tag; // 3    u4 bytes;}CONSTANT_Float_info {    u1 tag; // 4    u4 bytes;}CONSTANT_Long_info {    u1 tag; // 5    u4 high_bytes;    u4 low_bytes;}CONSTANT_Double_info {    u1 tag; // 6    u4 high_bytes;    u4 low_bytes;}CONSTANT_NameAndType_info {    u1 tag; // 12    u2 name_index;    u2 descriptor_index;}CONSTANT_Utf8_info {    u1 tag; // 1    u2 length;    u1 bytes[length];}CONSTANT_MethodHandle_info {    u1 tag; // 15    u1 reference_kind;    u2 reference_index;}CONSTANT_MethodType_info {    u1 tag; // 16    u2 descriptor_index;}CONSTANT_InvokeDynamic_info {    u1 tag; // 18    u2 bootstrap_method_attr_index;    u2 name_and_type_index;}

访问标识符:

2f40cad92c20ab4ac7c9a89e01419a81.png

访问标识符

下面我们通过一个简单的Class文件进行分析,通过实际动手解析加深我们对Class字节码文件格式的理解和认识。解析实例方法中的Code属性内容时需要了解一些Jvm中的指令,后续Jvm指令集整理好后贴出

源码:

package com.sourcecode.springboot.tomcatwar;public class ClassTest {    private String s1 = "abc";    private static final String s2 = "edf";    public static void main(String[] args) {}    public String print(String msg) {        System.err.println(msg);        return msg;    }}

javap展示结果:(占用篇幅多,删掉了main方法和实例方法,保留了构造方法,可自行执行命令查看完整结果)

$ javap -p -v ClassTest.classpublic class com.sourcecode.springboot.tomcatwar.ClassTest  minor version: 0  major version: 52  flags: ACC_PUBLIC, ACC_SUPERConstant pool:   #1 = Methodref          #7.#30         // java/lang/Object."":()V   #2 = String             #31            // abc   #3 = Fieldref           #6.#32         // com/sourcecode/springboot/tomcatwar/ClassTest.s1:Ljava/lang/String;   #4 = Fieldref           #33.#34        // java/lang/System.err:Ljava/io/PrintStream;   #5 = Methodref          #35.#36        // java/io/PrintStream.println:(Ljava/lang/String;)V   #6 = Class              #37            // com/sourcecode/springboot/tomcatwar/ClassTest   #7 = Class              #38            // java/lang/Object   #8 = Utf8               s1   #9 = Utf8               Ljava/lang/String;  #10 = Utf8               s2  #11 = Utf8               ConstantValue  #12 = String             #39            // edf  #13 = Utf8                 #14 = Utf8               ()V  #15 = Utf8               Code  #16 = Utf8               LineNumberTable  #17 = Utf8               LocalVariableTable  #18 = Utf8               this  #19 = Utf8               Lcom/sourcecode/springboot/tomcatwar/ClassTest;  #20 = Utf8               main  #21 = Utf8               ([Ljava/lang/String;)V  #22 = Utf8               args  #23 = Utf8               [Ljava/lang/String;  #24 = Utf8               MethodParameters  #25 = Utf8               print  #26 = Utf8               (Ljava/lang/String;)Ljava/lang/String;  #27 = Utf8               msg  #28 = Utf8               SourceFile  #29 = Utf8               ClassTest.java  #30 = NameAndType        #13:#14        // "":()V  #31 = Utf8               abc  #32 = NameAndType        #8:#9          // s1:Ljava/lang/String;  #33 = Class              #40            // java/lang/System  #34 = NameAndType        #41:#42        // err:Ljava/io/PrintStream;  #35 = Class              #43            // java/io/PrintStream  #36 = NameAndType        #44:#45        // println:(Ljava/lang/String;)V  #37 = Utf8               com/sourcecode/springboot/tomcatwar/ClassTest  #38 = Utf8               java/lang/Object  #39 = Utf8               edf  #40 = Utf8               java/lang/System  #41 = Utf8               err  #42 = Utf8               Ljava/io/PrintStream;  #43 = Utf8               java/io/PrintStream  #44 = Utf8               println  #45 = Utf8               (Ljava/lang/String;)V{  private java.lang.String s1;    descriptor: Ljava/lang/String;    flags: ACC_PRIVATE  private static final java.lang.String s2;    descriptor: Ljava/lang/String;    flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL    ConstantValue: String edf  public com.sourcecode.springboot.tomcatwar.ClassTest();    descriptor: ()V    flags: ACC_PUBLIC    Code:      stack=2, locals=1, args_size=1         0: aload_0         1: invokespecial #1                  // Method java/lang/Object."":()V         4: aload_0         5: ldc           #2                  // String abc         7: putfield      #3                  // Field s1:Ljava/lang/String;        10: return      LineNumberTable:        line 3: 0        line 4: 4      LocalVariableTable:        Start  Length  Slot  Name   Signature            0      11     0  this   Lcom/sourcecode/springboot/tomcatwar/ClassTest;  }SourceFile: "ClassTest.java"

魔数、主次版本、常量池数据项个数解析

ec1be57152abca36ba06e268f3fdb22b.png

魔数、主次版本、常量池数据项个数解析

常量池中常量数据项解析:

根据字节码文件第一行偏移量为OA处的十六进制为A=10,说明这个常量数据项的tag=10,找到对应的常量类型CONSTANT_Methodref_info,该方法引用类型的数据格式如下:

CONSTANT_Methodref_info {

u1 tag; // 10

u2 class_index;

u2 name_and_type_index;

}

可知后面两个字节0x0007 = 7代表class_index,说明该方法所在类的信息指向常量池索引为7的常量,再后面两个字节0x001E = 30代表name_and_type_index,说明该方法的名称及类型信息指向常量池中索引为30的常量。

按照上面解析常量池数据项的方式,将常量池中的所有数据项解析出来,发现解析出的信息和使用javap命令查看class文件展示的常量池信息一致:

2a0d558dbfbecc5f0d1c51cf14f59aa7.png

字节码常量池数据项解析

78ea764b47a80c7457ccbd1818f2dc50.png

javap显示常量池信息

访问标志解析:

8fa0a6f9f141b9c381551c3200c1455a.png

access_flags访问标志解析

this_class、super_class、interfaces_count、interfaces[]、fields_count数据项解析:

b8ce3f2bfa62dbf779c4b959b3e3e35f.png

this_class、super_class、interfaces_count、interface[]、fields_count数据项解析

attribute_info数据格式(在字段、方法及Class属性中将会使用到):

attribute_info {    u2 attribute_name_index;    u4 attribute_length;    u1 info[attribute_length];}ConstantValue_attribute {    u2 attribute_name_index;    u4 attribute_length;    u2 constantvalue_index;}

field_info:fields[fields_count]数据项解析:

根据上文分析可知,该Class文件有2个字段信息,因此后面有两个连续的field_info类型的数据,field_info的数据格式:

field_info {    u2             access_flags;    u2             name_index;    u2             descriptor_index;    u2             attributes_count;    attribute_info attributes[attributes_count];}

字段数据项解析如下图:

147c93b3839fdd9c594b8316ccc6b5b1.png

field_info及field_info中的attribute_info解析

methods_count、methods[]数据项解析:

method_info数据格式:

method_info {    u2             access_flags;    u2             name_index;    u2             descriptor_index;    u2             attributes_count;    attribute_info attributes[attributes_count];}

如果不是抽象方法时,方法中在编译后,在Class文件中的该方法信息的属性表中会存在Code属性,Code_attribute数据格式为:

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];}

方法method_info解析:

63bfdc79722c88d149ad5e03608fbb45.png

方法method_info解析_1

bdc6b9616ea7ecbb1cf47a1a1ee5bf95.png

方法method_info中的code属性解析

可以看到解析结果和通过javap展示的结果一致:

b87c25e333ffaa7c5f502c9e09e445a7.png

javap_构造方法展示

后面继续补充完善!!!

attributes_count数据项解析:

attributes[]数据项解析:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值