CHAPTER 4 The class File Format
这一章从来就没有认真看过,今天看了几个小时,头都大了。12.29号继续。
1、自己动手查看.class文件的16进制、10进制和char表示。编写一个最简单的C程序就行了。
程序目标:输入当前目录中的.class文件(不要输入.class后缀),其他表示保存到文件byteCode.txt中。
程序1.exe:只要16进制的表示。
程序2.exe:方便起见,对照察看16进制、10进制表示。
程序3.exe:方便起见,对照察看16进制、10进制和char表示。其代码如下
#include <stdio.h>
#include <string.h>
void main(){
FILE *fpr, *fpw; int i;
char str[80];
printf("enter .class file name:\n");
scanf("%s",str);
char ext[8]={".class"};
strcat(str,ext);
fpr = fopen(str,"rb");
fpw = fopen("byteCode.txt","wb+");
while ((i=fgetc(fpr)) != EOF){
fprintf(fpw,"%x\t%d\t%c\n",i,i,i);
}
fclose(fpr);fclose(fpw);
}
2、写一个最没有用的Java程序AAA.java
public class AAA{
}
编译成.class,执行1.exe后得到byteCode.txt。
ca fe ba be 0 0 0 32 0 10 a 0 3 0 d 7 0 e 7 0 f 1 0 6 3c 69 6e 69 74 3e 1 0 3 28 29 56 1 0 4 43 6f 64 65 1 0 f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 1 0 12 4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 1 0 4 74 68 69 73 1 0 5 4c 41 41 41 3b 1 0 a 53 6f 75 72 63 65 46 69 6c 65 1 0 8 41 41 41 2e 6a 61 76 61 c 0 4 0 5 1 0 3 41 41 41 1 0 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 0 21 0 2 0 3 0 0 0 0 0 1 0 1 0 4 0 5 0 1 0 6 0 0 0 2f 0 1 0 1 0 0 0 5 2a b7 0 1 b1 0 0 0 2 0 7 0 0 0 6 0 1 0 0 0 1 0 8 0 0 0 c 0 1 0 0 0 5 0 9 0 a 0 0 0 1 0 b 0 0 0 2 0 c
A class file consists of a stream of 8-bit bytes. 每字节一行,这个byteCode.txt有234多行,yqj2065要byte by byte 的看看这些东西。过一遍后,再用jclasslib学习较复杂的例子。
3、The class File Format
Each class file contains the definition of a single class or interface.所以.class文件要表示该类/接口的种种info,使用了u1, u2, and u4 (class文件的)类型和类似C结构的pseudostructures如ClassFile、cp_info 、field_info 、method_info 和attribute_info 等等。
byte by byte
一个class文件由单一的 ClassFile structure构成。
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
1、前10个字节。
ca fe ba be 0 0 0 32 0 10
传说中的u4 magic,值为0xca fe ba be读作cafe babe,为什么不是Jame sGos(ling )。
0 0 0 32 //u2 minor_version, u2 major_version 分别是0x0,0x32即50,version0.50
0 10 // u2 constant_pool_count 这一项的值有16.constant_pool[]中有16-1 ==15项
2、cp_info部分。The constant_pool is a table of structures (§4.4) representing various string constants, class and interface names, field names, and other constants that are referred to within the ClassFile structure and its substructures.基本形式为:
cp_info {
u1 tag;
u1 info[];//这个部分随着tag值不同,由对应项替换。
}
------------------constant_pool[]--------------------
对照察看16进制、10进制表示:
a 10 u1 tag 查表10对应CONSTANT_Methodref(10 ),随后的u2+u2是CONSTANT_Methodref_info
0 0
3 3
0 0
d 13
方便起见,现在开始用伪结构表示。使用10进制表示(如果是16进制,按惯例加以前缀0x)
CONSTANT_Methodref_info { //#1 index in constant_pool[]
u1 tag; // 10 ->CONSTANT_Methodref
u2 class_index; // 0 3 指向#3constant_pool[]实体
u2 name_and_type_index;// 0 13 指向#13constant_pool[]实体
}//参见4.4.2
CONSTANT_Class_info { //#2
u1 tag; //7
u2 name_index; //0 14 指向constant_pool[]中的#14实体
}
CONSTANT_Class_info { //#3
u1 tag; //7
u2 name_index; //0 15
}
接下来,要对照察看16进制、10进制和char表示了。因为是CONSTANT_Utf8_info Structure。
1 1
0 0
6 6
3c 60 <
69 105 i
6e 110 n
69 105 i
74 116 t
3e 62 >
CONSTANT_Utf8_info { //#4
u1 tag; //1
u2 length; //0 6 byte数组中有6个字符
u1 bytes[length];// 0x3c 69 6e 69 74 62 即<init>
}
CONSTANT_Utf8_info {//#5
u1 tag; //1
u2 length; //0 3
u1 bytes[length];// ()V
}
同样,#6即Code、#7即LineNumberTable,#8即LocalVariableTable,
#9即this,#10即LAAA; ,#11即SourceFile,#12即AAA.java
CONSTANT_NameAndType_info {#13
u1 tag; //12
u2 name_index; // 0 4 即指向#4的<init>
u2 descriptor_index; //0 5 即()V
}
CONSTANT_Utf8_info:#14即AAA、#15即java/lang/Object //共15个
The constant_pool table is indexed from 1 to constant_pool_count-1.
------------------constant_pool[]--------------------
3、中间若干项,看ClassFile structure那个大图。
接下来是u2 access_flags;直到u2 methods_count;
0 0
21 33 //u2 access_flags;值为0x0021
//即0x0020 |0x0001,也就是ACC_SUPER和ACC_PUBLIC 。AAA是public
0 0
2 2 //u2 this_class; 值为2指向constant_pool[]中的#2,后者指向#14,即AAA
0 0
3 3 //u2 super_class; //#3->#15即java/lang/Object
0 0
0 0 //u2 interfaces_count; 值为0x00 00,没有下一项。
u2 interfaces[interfaces_count];
0 0
0 0 //u2 fields_count;
field_info fields[fields_count];
0 0
1 1 //u2 methods_count;值为0x00 01,一个方法
4、method_info。参考4.6 Methods
Each method, 包括each instance /the class or interface initialization method (§3.9), 都由a method_info structure说明. No two methods in one class file may have the same name and descriptor (§4.3.3).在4.3.3 Method Descriptors中说明了一般格式:
( ParameterDescriptor* ) ReturnDescriptor
基本形式为:
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
这个部分字节如下:
0 0
1 1 //u2 access_flags;0 1 即ACC_PUBLIC
0 0
4 4 //u2 name_index; 0 4 指向constant_pool[]中的#4,即<init>
0 0
5 5 //u2 descriptor_index; 0 5 指向#5即()V 表示void
0 0
1 1 //u2 attributes_count; 0 1表示有一个属性。转入attribute_info结构。
5、attribute_info,参考4.7 Attributes
这个attributes广泛用于the class file format中的ClassFile, field_info , method_info 和 Code_attribute (§4.7.3) structures 。一般形式为:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length]; //随着attribute_name_index不同由由对应项替换。
}
由于我们这里遇到的是4.7.3 The Code Attribute,使用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];
}
这个部分字节如下:
0 0
6 6 //u2 attribute_name_index; 0 6即Code所有的方法/构造器都有这个属性
0 0
0 0
0 0
2f 47 //u4 attribute_length;47 下面的47字节属于本attribute
0 0
1 1 //u2 max_stack; 0 1
0 0
1 1 //u2 max_locals。0 1
0 0
0 0
0 0
5 5 //u4 code_length;下面的5字节属于本Code
2a 42
b7 183
0 0
1 1
b1 177 //code[5]; 0x 2a b7 00 01 b1 是什么东西?
0 0
0 0 //u2 exception_table_length; 没有exception_table
0 0
2 2 // u2 attributes_count;嵌套了2个属性。
A Code attribute 常常有自己的属性,Currently, the LineNumberTable (§4.7.8) and LocalVariableTable (§4.7.9) attributes, both of which contain debugging information, are defined and used with the Code attribute.
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];
}
0 0
7 7 //u2 attribute_name_index; 0 7 #7即LineNumberTable
0 0
0 0
0 0
6 6 //u4 attribute_length;下面的6字节属于本attribute
0 0
1 1 //u2 line_number_table_length;即line_number_table[1];
0 0
0 0 //u2 start_pc;
0 0
1 1 //u2 line_number;
又一个嵌套属性
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 descriptor_index;
u2 index;
} local_variable_table[local_variable_table_length];
}
0 0
8 8 //u2 attribute_name_index; 0 8 #8即LocalVariableTable
0 0
0 0
0 0
c 12 //u4 attribute_length;下面的12字节属于本attribute
0 0
1 1 //u2 local_variable_table_length;即local_variable_table[1];
0 0
0 0 //u2 start_pc;
0 0
5 5 //u2 length;
0 0
9 9 //u2 name_index; #9即this
0 0
a 10 //u2 descriptor_index; #10即LAAA;
0 0
0 0 //u2 index;
6、最后是4.7.7 The SourceFile Attribute
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index;
}
0 0
1 1 //看ClassFile structure那个大图。u2 attributes_count;本class文件的属性1个。
0 0
b 11 //u2 attribute_name_index;#11即SourceFile
0 0
0 0
0 0
2 2 //u4 attribute_length;
0 0
c 12 //u2 sourcefile_index;#12即AAA.java
大功告成!