分享

Matrix - 与 Java 共舞 - JVM之class文件结构

 zhuge 2006-04-10

                               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中的有效索引值,对于in
terface必须为非0
            u2 interfaces_count;    //superinterfaces的个数
            u2 interfaces[interfaces_count];  //计数[0,count-1) 对应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分别对应结构变化为
        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位也必须被设置,当然也可以设置AC
C_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_inf
o描述。


            u2 descriptor_index; //constant_pool中的索引,对应于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位,且不能置其他位。
           其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应
当忽略他们。




    methods指明了类中的所有方法。

        method_info {
                    u2 access_flags;
                    u2 name_index;   //指向constant_pool的入口,对应为CONSTANT_
Utf8_info
                    u2 descriptor_index;  //指向constant_pool的入口,对应为CONS
TANT_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_U
tf8_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_Ut
f8_info 结构。
           }

      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应为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_p
c)部分
                        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+lengt
h]
                                   //时变量必须被赋值??
                        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   .....<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 (注意,不是高字节在前,别犯职业病!
)
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 :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>" : 构造
函数
8.  01 00 03 28 29 56   ...()V   函数,无参数
                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   函数,参数为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>  表明当前描述构
造函数
     00 08     descriptor_index;
     00 01     attributes_count;
     00 09     attribute_name_index   0x09 看看constant_pool的第9项,简单明了Cod


e !!
     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_count
00 0d     attribute_name_index   属性为SourceFile
00 00 00 02  attribute_length
00 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 :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

       故该指令调用了 java.io.PrintStream.println(java.lang.String)
           而参数则为 ldc #3 加载的 "Hello World!"
0xb1  : return



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多