상세 컨텐츠

본문 제목

Java Class File Format 읽는 방법

개발 관련(Computer Science)

by Director J 2018. 9. 30. 06:56

본문

안녕하세요. 이 글은 웹으로 읽는 것을 추천드립니다.


자바 클래스 파일 읽는 방법에 대해서 알려드리겠습니다.


보통 자바를 컴파일하고 실행할 때, Java Class라는 파일을 생성합니다. 


Raw파일로 일반 에디터(ex. Atom)으로 읽을 수 없고, 리눅스 OS 시스템의 경우,  


CLI에서 "od -tx1 파일명"이라는 방식으로 읽을 수 있습니다.


그럼 간단한 예시로 알려드리겠습니다.


$ od -tx1 Runnable.class

0000000 ca fe ba be 00 00 00 34 00 0b 07 00 09 07 00 0a

0000020 01 00 03 72 75 6e 01 00 03 28 29 56 01 00 0a 53

0000040 6f 75 72 63 65 46 69 6c 65 01 00 0d 52 75 6e 6e

0000060 61 62 6c 65 2e 6a 61 76 61 01 00 19 52 75 6e 74

0000100 69 6d 65 56 69 73 69 62 6c 65 41 6e 6e 6f 74 61

0000120 74 69 6f 6e 73 01 00 1f 4c 6a 61 76 61 2f 6c 61

0000140 6e 67 2f 46 75 6e 63 74 69 6f 6e 61 6c 49 6e 74

0000160 65 72 66 61 63 65 3b 01 00 12 6a 61 76 61 2f 6c

0000200 61 6e 67 2f 52 75 6e 6e 61 62 6c 65 01 00 10 6a

0000220 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 06

0000240 01 00 01 00 02 00 00 00 00 00 01 04 01 00 03 00

0000260 04 00 00 00 02 00 05 00 00 00 02 00 06 00 07 00

0000300 00 00 06 00 01 00 08 00 00

0000311


그럼 여기서 읽는 방식에 대해서 알려드리겠습니다.


자바 공식 홈페이지에 있는 관련 도큐먼트를 보면 이런 내용이 있습니다.

(관련 홈페이지 URL: Chapter 4. The class File Format)


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

이것은 자바의 자료구조에 대해서 설명하는 부분입니다.


u4는 4바이트로 된 자료라는 것이고, u2는 2바이트로 된 자료라는 뜻입니다.


그래서 Magic은 4바이트이므로 ca fe ba be 입니다.

(참고로, 자바의 Magic은 항상 CAFE BABE입니다. )


만약에 Magic이 CAFE BABE가 아닐 경우, 이 파일은 자바 클래스 파일이 아님을 뜻합니다.


그리고 그 다음 2바이트는 Minor_version을 뜻하는 것이고, 다음 2바이트는 Major_version을 뜻하는 것입니다.


그래서 순서를 보자면, Magic 4바이트 -> Minor_version 2바이트 -> Major_version 2바이트 -> 등등 이렇습니다.


문제가 되는 부분은 Constant_pool[constant_pool_count - 1]을 읽는 방법입니다.


그 바로 앞에 constant_pool_count라는 2바이트로 된 데이터가 있는데 보통 이를 통해서, 다음에 오는 데이터, 


즉, Constant_pool[constant_pool_count - 1]이 몇개 있는지 알 수 있습니다. 예를 들어, 00 0b개가 있을 경우, 


16진법 0b는 11이므로 Constant_pool은 10개의 태그와 데이터를 가진다는 사실을 알 수 있습니다.


그럼 Constant_pool[constant_pool_count - 1]은 어떻게 읽을 수 있을까요?


Tag byteAdditional bytesDescription of constant
12+x bytes
(variable)
UTF-8 (Unicode) string: a character string prefixed by a 16-bit number (type u2) indicating the number of bytes in the encoded string which immediately follows (which may be different than the number of characters). Note that the encoding used is not actually UTF-8, but involves a slight modification of the Unicode standard encoding form.
34 bytesInteger: a signed 32-bit two's complement number in big-endian format
44 bytesFloat: a 32-bit single-precision IEEE 754 floating-point number
58 bytesLong: a signed 64-bit two's complement number in big-endian format (takes two slots in the constant pool table)
68 bytesDouble: a 64-bit double-precision IEEE 754 floating-point number (takes two slots in the constant pool table)
72 bytesClass reference: an index within the constant pool to a UTF-8 string containing the fully qualified class name (in internal format) (big-endian)
82 bytesString reference: an index within the constant pool to a UTF-8 string (big-endian too)
94 bytesField reference: two indexes within the constant pool, the first pointing to a Class reference, the second to a Name and Type descriptor. (big-endian)
104 bytesMethod reference: two indexes within the constant pool, the first pointing to a Class reference, the second to a Name and Type descriptor. (big-endian)
114 bytesInterface method reference: two indexes within the constant pool, the first pointing to a Class reference, the second to a Name and Type descriptor. (big-endian)
124 bytesName and type descriptor: two indexes to UTF-8 strings within the constant pool, the first representing a name (identifier) and the second a specially encoded type descriptor.
153 bytesMethod handle: this structure is used to represent a method handle and consists of one byte of type descriptor, followed by an index within the constant pool.[5]
162 bytesMethod type: this structure is used to represent a method type, and consists of an index within the constant pool.[5]
184 bytesInvokeDynamic: this is used by an invokedynamic instruction to specify a bootstrap method, the dynamic invocation name, the argument and return types of the call, and optionally, a sequence of additional constants called static arguments to the bootstrap method.[5]

다행스럽게도, Java Class File 위키백과에 자세하게 나와있습니다.

(관련 홈페이지 URL : Java class file)


각각의 Constant 테이블은 1개의 태그를 가지는데 그 태그에 따라서 읽어야하는 데이터가 달라지는 것입니다. 


예를 들어, 태그가 07인 경우, 위의 표에서 볼 수 있듯이 2개의 바이트를 추가로 데이터로 가지고 있습니다.


태그가 01인 경우, UTF8을 뜻하는데 태그 후에 2개의 바이트를 읽고, 그 바이트에 따라서,


추가로 데이터를 더 읽어야 합니다. 예를 들어: 


01 00 03 72 75 6e의 경우 '01' 태그를 읽고 2바이트를 읽습니다. 


그럼 00 03이라는 2개의 바이트를 추가로 읽을 수 있는데, 이는 3개의 바이트를 추가로 취한다는 뜻입니다.


그래서 그 1개의 Constant_pool[0]은 즉 이렇게 됩니다:


$ od -tx1 Runnable.class

0000000 ca fe ba be 00 00 00 34 00 0b 07 00 09 07 00 0a

0000020 01 00 03 72 75 6e 01 00 03 28 29 56 01 00 0a 53

0000040 6f 75 72 63 65 46 69 6c 65 01 00 0d 52 75 6e 6e

0000060 61 62 6c 65 2e 6a 61 76 61 01 00 19 52 75 6e 74

0000100 69 6d 65 56 69 73 69 62 6c 65 41 6e 6e 6f 74 61

0000120 74 69 6f 6e 73 01 00 1f 4c 6a 61 76 61 2f 6c 61

0000140 6e 67 2f 46 75 6e 63 74 69 6f 6e 61 6c 49 6e 74

0000160 65 72 66 61 63 65 3b 01 00 12 6a 61 76 61 2f 6c

0000200 61 6e 67 2f 52 75 6e 6e 61 62 6c 65 01 00 10 6a

0000220 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 06

0000240 01 00 01 00 02 00 00 00 00 00 01 04 01 00 03 00

0000260 04 00 00 00 02 00 05 00 00 00 02 00 06 00 07 00

0000300 00 00 06 00 01 00 08 00 00

0000311


다음 Constant_pool[1]은:


$ od -tx1 Runnable.class

0000000 ca fe ba be 00 00 00 34 00 0b 07 00 09 07 00 0a

0000020 01 00 03 72 75 6e 01 00 03 28 29 56 01 00 0a 53

0000040 6f 75 72 63 65 46 69 6c 65 01 00 0d 52 75 6e 6e

0000060 61 62 6c 65 2e 6a 61 76 61 01 00 19 52 75 6e 74

0000100 69 6d 65 56 69 73 69 62 6c 65 41 6e 6e 6f 74 61

0000120 74 69 6f 6e 73 01 00 1f 4c 6a 61 76 61 2f 6c 61

0000140 6e 67 2f 46 75 6e 63 74 69 6f 6e 61 6c 49 6e 74

0000160 65 72 66 61 63 65 3b 01 00 12 6a 61 76 61 2f 6c

0000200 61 6e 67 2f 52 75 6e 6e 61 62 6c 65 01 00 10 6a

0000220 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 06

0000240 01 00 01 00 02 00 00 00 00 00 01 04 01 00 03 00

0000260 04 00 00 00 02 00 05 00 00 00 02 00 06 00 07 00

0000300 00 00 06 00 01 00 08 00 00

0000311


다음 Constant_pool[2]는:


$ od -tx1 Runnable.class

0000000 ca fe ba be 00 00 00 34 00 0b 07 00 09 07 00 0a

0000020 01 00 03 72 75 6e 01 00 03 28 29 56 01 00 0a 53

0000040 6f 75 72 63 65 46 69 6c 65 01 00 0d 52 75 6e 6e

0000060 61 62 6c 65 2e 6a 61 76 61 01 00 19 52 75 6e 74

0000100 69 6d 65 56 69 73 69 62 6c 65 41 6e 6e 6f 74 61

0000120 74 69 6f 6e 73 01 00 1f 4c 6a 61 76 61 2f 6c 61

0000140 6e 67 2f 46 75 6e 63 74 69 6f 6e 61 6c 49 6e 74

0000160 65 72 66 61 63 65 3b 01 00 12 6a 61 76 61 2f 6c

0000200 61 6e 67 2f 52 75 6e 6e 61 62 6c 65 01 00 10 6a

0000220 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 06

0000240 01 00 01 00 02 00 00 00 00 00 01 04 01 00 03 00

0000260 04 00 00 00 02 00 05 00 00 00 02 00 06 00 07 00

0000300 00 00 06 00 01 00 08 00 00

0000311


그렇게 쭉쭉 10개의 태그를 읽게되면 그 후에는 access_flags를 만나게 됩니다. 이 자료의 경우:


$ od -tx1 Runnable.class

0000000 ca fe ba be 00 00 00 34 00 0b 07 00 09 07 00 0a

0000020 01 00 03 72 75 6e 01 00 03 28 29 56 01 00 0a 53

0000040 6f 75 72 63 65 46 69 6c 65 01 00 0d 52 75 6e 6e

0000060 61 62 6c 65 2e 6a 61 76 61 01 00 19 52 75 6e 74

0000100 69 6d 65 56 69 73 69 62 6c 65 41 6e 6e 6f 74 61

0000120 74 69 6f 6e 73 01 00 1f 4c 6a 61 76 61 2f 6c 61

0000140 6e 67 2f 46 75 6e 63 74 69 6f 6e 61 6c 49 6e 74

0000160 65 72 66 61 63 65 3b 01 00 12 6a 61 76 61 2f 6c

0000200 61 6e 67 2f 52 75 6e 6e 61 62 6c 65 01 00 10 6a

0000220 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 06

0000240 01 00 01 00 02 00 00 00 00 00 01 04 01 00 03 00

0000260 04 00 00 00 02 00 05 00 00 00 02 00 06 00 07 00

0000300 00 00 06 00 01 00 08 00 00

0000311


access_flags는 06 01입니다. 이와 같은 방식으로 this_class, super_class, interfaces_count 등등을 읽으면 됩니다.


안타깝게도 Programming을 하면서 한국어로 된 자료를 찾기가 어려운게 현실입니다.


조금이라도 빠른 이해에 도움이 되었으면 좋겠습니다. 미국에 있는 공대생들 화이팅입니다.


반응형

관련글 더보기