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];
}
jvm specification second edition에서는 클래스 파일의 구조를 위와 같이 표현해 놓았으며 이를 분석해 보면 다음과 같다.
u2 -> unsigned 2byte
u4 -> unsigned 4byte
magic => 매직넘버 (일반적으로 0xcafebabe 인 고정값 )
minor_version => jdk의 minor 버전
major_version => jdk의 major 버전
constant_pool_count => 전체 constant pool의 개수를 나타내며 실제로 constant pool의 개수보다 1개가 많은 값을 가진다.
cp_info constant_pool[] => 실제 constant pool array를 나타내며 다음과 같은 종류가 있다.
cp_info {
u1 tag;
u1 info[];
}
cp_info 의 tag 값이 constant type을 나타내며 각각의 type에 따라 info 에 나오 는 구조가 달라지게 된다.
access flag => class 의 접근자를 나타낸다.
this_class, super_class => class의 이름. 다만 여러 상수값들은 전 부 constant_pool 에 저장되어 있으므로 실제로는 constant_pool의 특정 index값 만을 가지고 있다.
interface_count => 클래스 파일이 implements를 사용한 경우 interface의 개수를 나타내게 된다.
interfaces[] => 실제 인터페이스 정보를 가지는 구조체
Constant Type Value
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Method ref 10
CONSTANT_Inter faceMethod ref 11
CONSTANT_Str ing 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
fields_count => 이후에 나올 클래스 멤버 변수등의 field의 개수
field_info fields[] => 실제 필드 정보를 가지는 구조체가 되며 field_info의 구조 는 다음과 같다.
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
field_info 는 변수에 대한 접근자, 이름, descriptor 등을 가지며 실제 필드의 내
용은 attribute_info 형태로 저장되어 있으며 attribute_info 에는 여러 종류가 있다.
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
attribute_info.attribute_name_index 는 attribute의 종류를 나타내며 attribute의 종류는 다음과 같다.
SourceFile , ConstantValue, Code , Exceptions , InnerClasses, Synthetic , LineNumberTable, LocalVariableTable, Deprecated attributes
이 값들은 constant pool에 utf-8 형태로 저장되어 있으며 따라서 attribute_name_index는 constant pool의 특정 index를 가리키게 된다.
실제 kvm의 class loader의 경우 attribute의 type이 결정되면 결정된 type에 맞게 attribute_length 만큼 info[] 정보를 읽어들이게 된다.
method_count => method 의 개수.
method_info methods[] => 실제 method의 정보를 나타내며 method_info 의 구 조는 다음과 같다.
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
access_flag => method 에 대한 접근자
name_index => method의 이름을 utf-8로 가지고 있는 constant pool에 대한 in dex
descriptor_index => method 구별을 위한 descriptor값을 utf-8로 가지고 있는
constant pool에 대한 index (method의 return 값은 descriptor에 포함되지 않음
)
attributes_count 와 attribute_info의 경우에는 field_info 와 동일
attributes_count와 attributes[] 가 한번더 나오며 이는 클래스 파일에 대한 추가적인 정보를 가진다. 이곳에는 주로 Code attribute, InnerClass attribute, Deprecated attribute, Synthetic attribute, SourceFile attribute등이 나온다.
직접 간단한 클래스를 작성하여 위의 사항들을 확인해보자.
public class DefaultClass {
private int filed;
public DefaultClass() {}
public void function() {}
}
위와 같은 DefaultClass.java를 컴파일한후 나오는 DefaultClass.class 파일을 바이너리로 열어서 확인해보면 다음과 같다.
0000000: cafe babe 0000 0032 0010 0a00 0300 0d07 .......2........
0000010: 000e 0700 0f01 0005 6669 6c65 6401 0001 ........filed...
0000020: 4901 0006 3c69 6e69 743e 0100 0328 2956 I...<init>...()V
0000030: 0100 0443 6f64 6501 000f 4c69 6e65 4e75 ...Code...LineNu
0000040: 6d62 6572 5461 626c 6501 0008 6675 6e63 mberTable...func
0000050: 7469 6f6e 0100 0a53 6f75 7263 6546 696c tion...SourceFil
0000060: 6501 0011 4465 6661 756c 7443 6c61 7373 e...DefaultClass
0000070: 2e6a 6176 610c 0006 0007 0100 0c44 6566 .java........Def
0000080: 6175 6c74 436c 6173 7301 0010 6a61 7661 aultClass...java
0000090: 2f6c 616e 672f 4f62 6a65 6374 0021 0002 /lang/Object.!..
00000a0: 0003 0000 0001 0002 0004 0005 0000 0002 ................
00000b0: 0001 0006 0007 0001 0008 0000 0021 0001 .............!..
00000c0: 0001 0000 0005 2ab7 0001 b100 0000 0100 ......*.........
00000d0: 0900 0000 0a00 0200 0000 0400 0400 0500 ................
00000e0: 0100 0a00 0700 0100 0800 0000 1900 0000 ................
00000f0: 0100 0000 01b1 0000 0001 0009 0000 0006 ................
0000100: 0001 0000 0009 0001 000b 0000 0002 000c ................
0000110: 0a .
이제 컴파일 후의 실제 class file 구조를 위의 스펙에 맞는지 확인해보자.
각각의 값은 다음과 같다.
MAGIC : cafe babe
minorVersion : 0000
majorVersion : 0031
constantPoolCount : 001c (28)
[constantPool]
0.Method tag : 0a (10) class_index : 0008 name&type_index : 0011 (17)
1.Class tag : 07 name_index : 0012
2.Method tag : 0a (10) class_index : 0002 name&type_index : 0011 (17)
3.Method tag : 0a (10) class_index : 0002 name&type_index : 0013 (19)
4.Method tag : 0a (10) class_index : 0002 name&type_index : 0014 (20)
5.Method tag : 0a (10) class_index : 0002 name&type_index : 0015 (21)
6.Class tag : 07 name_index : 0016
7.Class (22) tag : 07 name_index : 0017 (23)
8.UTF8 tag : 01 length : 0006 bytes[length] : 3c 69 6e 69 74 3e
9.UTF8 <init> tag : 01 length bytes[length] : 0003 : 28 29 56 ()V
10.UTF8 tag : 01 length : 0004 bytes[length] : 43 6f 64 65 Code tag : 01
11.UTF8 length bytes[length] : 000f (15) : 4c 69 6e 65 4e | 75 6d 62 65 72 | 54 61 62 6c 65
LineN umber Table
12.UTF8 tag : 01 length : 0004 bytes[length] : 6d 61 69 6e main
13.UTF8 tag : 01 length : 0016 (22) bytes[length] : 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 tag: 01
14.UTF8 length bytes[length] : 000a (10) : 53 6f 75 72 63 | 65 46 69 6c 65 SourceFile
15.UTF8 tag : 01 length : 000e ( 14 ) bytes[length] : 54 65 73 74 44 | 72 69 76 65 2e | 6a 61 76 61 TestDrive. java
16.NameAndType tag: 0c (12) name_index : 0009 descriptor_index: 000a (10)
17.UTF8 tag: 01 length: 0008 bytes[length] : 54 65 73 74 54 | 68 69 73 TestThis
18.NameAndType tag: 0c (12) name_index : 0018 (24) descriptor_index: 000a (10)
19.NameAndType tag: 0c (12) name_index : 0019 (25) descriptor_index: 000a (10)
20.NameAndType tag: 0c (12) name_index : 001a (26) descriptor_index: 001b (27)
21.UTF8 tag: 01 length: 0009 bytes[length] : 54 65 73 74 44 | 72 69 76 65 TestD rive
22.UTF8 tag: 01 length: 0010 (16) bytes[length] : 6a 61 76 61 2f | 6c 61 6e 67 2f | 4f 62 6a 65 63 | 74 java/ lang/ Objec t tag : 01
23.UTF8 length bytes[length]: 000a (10) :70 7269 6e74 |53 7461 7274 printStart
24.UTF8 tag: 01
length bytes[length]: 000a (10) :70 7269 6e74 |53 7570 6572 print Super
25.UTF8 tag : 01
length : 0003 bytes[length] : 41 64 64 Add
26.UTF8 tag : 01
length : 0005 bytes[length] : 28 49 49 29 49 (II)I
access_flag this_class super_class interfaces_count fields_count methods_count
: 0021 ( ACC_PUBLIC | ACC_SUPER ) : 0007
: 0008 : 0000 : 0000
: 0002 [Method#1]
access_flag: 0001 (ACC_PUBLIC)
name_index descriptor_index attr_count: 0009 : 000a (10): 0001
attr_name_index : 000b (11) => "Code"
[Code Attr]
attr_length max_stack max_locals code_length code[code_length] : 2a b7 00 01 b1 exception_table_length : 0000 attr_count : 0001
[LineNumTable] attr_name_index : 000c (12) => "LineNumberTable" attr_length : 0000 0006 line_number_table_length : 0001 start_pc : 0000 line_number : 0012 (18)
[Method#2] access_flag name_index descriptor_index attr_count
: 0009 (ACC_PUBLIC | ACC_STATIC ) : 000d (13)
: 000e (14) : 0001
[Code Attr] attr_name_index attr_length max_stack max_locals code_length code[code_length]
10 0a | b6 00 06 57 b1 exception_table_length
: 0000
: 0000 001d (28) : 0001
: 0001 : 0000 0005
: 000b (11) => "Code" : 0000 0041 (65)
: 0003 : 0002
: 0000 0019 (25) : bb 00 02 59 b7 | 00 03 4c 2b b6 | 00 04 2b b6 00 | 05 2b 08
attr_count : 0001 [LineNumberTable Attr] attr_name_index : 000c (12) => "LineNumberTable" attr_length : 0000 0016 line_number_table_length: 0005
[ line_number_table[0] ] start_pc : 0000 line_number : 0016
[ line_number_table[1] ] start_pc : 0008 line_number : 0018
[ line_number_table[2] ] start_pc : 000c line_number : 0019
[ line_number_table[3] attr_count attr_name_index attr_length sourcefile_index
end of file
start_pc : 0010 line_number : 001b
[ line_number_table[4] ] start_pc : 0018 line_number : 001d
: 0001 : 000f (15) => SourceFile
: 0000 0002 : 0010 (16) => TestDrive.java
: 0a