49
Javaクラスファイル の読み Javaクラスファイル 2014/12/20 初者向け 1

Javaクラスファイルの読み方

Embed Size (px)

Citation preview

Page 1: Javaクラスファイルの読み方

Javaクラスファイル  の読み⽅方Javaクラスファイル⼊入⾨門  

2014/12/20

初⼼心者向け

1

Page 2: Javaクラスファイルの読み方

このセッションの流れ

2

• JVM仕様とは何かについて • javapを使ってみましょう • classファイルフォーマットの読み方概要 • 後続セッションでの実践の準備

http://dev.classmethod.jp/server-side/java/classfile-reading/

追記: このセッションのフォローアップ記事を書きました Javaのクラスファイルをjavapとバイナリエディタで読む

Page 3: Javaクラスファイルの読み方

Javaのコンパイルと実行

3

ハードウェア

OS OS OS

ハードウェア ハードウェア

JVM JVM JVM

中間コード 中間コード 中間コード

プラットフォーム共通

.class .class .class

中間コード.class

Javaプログラム

.java コンパイル

実行

Page 4: Javaクラスファイルの読み方

JVM

4

ハードウェア

OS OS OS

ハードウェア ハードウェア

JVM JVM JVM

中間コード 中間コード 中間コード

プラットフォーム共通JVM プラットフォーム依存

.class .class .class

Page 5: Javaクラスファイルの読み方

JVM仕様とは

5

JVM仕様は,実装の詳細には踏み込まない

入力であるクラスファイルのデータ構造と 出力である振る舞いのルールを定義するもの

このルールを満たす実装をJVMと呼ぶ 逆に言うと,特定のJVMの仕様を定めたものではない

Page 6: Javaクラスファイルの読み方

classファイル・フォーマットとは

6

Javaのクラスファイルを表現するバイナリの並びを定義したもの

u4 magic

u2 minor_version

u2 major_version

u2 constant_pool_cont

など

Page 7: Javaクラスファイルの読み方

2つのツールの違い

7

javap

バイナリエディタ

バイナリデータを読みやすく整形して表示する 入力として想定するのは,ファイルなら何でも

バイナリデータをJavaのclassファイルとして解釈し,JVM仕様で定義されたデータ構造とのマッピングを表示する 入力として想定するのは,Java classファイルのみ

どちらもバイナリデータを読み込む点は共通

Page 8: Javaクラスファイルの読み方

javap

8

Javaの標準ツール OpenJDKベースのJDKに入っている

コマンドラインで実行する ターミナル,iTerm,コマンドプロンプト(Windows)

Javaクラスファイルを逆アセンブルするために使う

Page 9: Javaクラスファイルの読み方

どんなときにjavapを使うか

9

• 複数のコンパイラを使う状況で,コンパイラごとに出力される中間コードの差分を見たいとき

• 処理系を作る際に,期待する入力と実際の中間コードの差分を見たいとき

バイナリとは異なる粒度でファイル間の差分を見る時に 使うのではないかと思います そういった作業をしなければ使う機会はあまりないと思います

(例)

Page 10: Javaクラスファイルの読み方

javapを使ってみましょう

10

Page 11: Javaクラスファイルの読み方

javapを使う前提条件

11

• Javaがインストールされていること • OpenJDK系のJDKがインストールされていること • JREだけでなく,JDKが必要です

PCをお持ちでない方は,javapの出力内容の説明に入るまで少々お待ちください.

Page 12: Javaクラスファイルの読み方

javapを試す手順

12

1. HelloWorldを出力するJavaプログラムHello.javaを書いて,コンパイルしてください

2. 生成されたHello.classに対して,javapを実行してください

% vi Hello.java class Hello{ public static void main(String[] args){ System.out.pintln(“Hello World!”); } } !% javac Hello.java % javap Hello

Page 13: Javaクラスファイルの読み方

javapの出力例

13

% javap Hello Compiled from "Hello.java" class Hello { Hello(); public static void main(java.lang.String[]); }

次のような出力が得られましたか?

そのままでは情報量が少ないため,vオプションをつけてもう一度実行してください

% javap -v Hello

Page 14: Javaクラスファイルの読み方

javapの出力例の説明

14

javapの出力は,JVM仕様を参照しながらバイナリを読めるようになった後の方が理解しやすい javapの出力はすでにJVM仕様とマッピングされているが,バイナリエディタを使って見る作業では自分でマッピングするため

このタイミングで詳細が分からなくてもこだわらず, どんな項目が出力されるかを眺めておいてください どうしても気になる時は,JVM仕様内を検索してみてください

(注意事項)

Page 15: Javaクラスファイルの読み方

15

Classfile /path/to/classfile/Hello.class Last modified 2014/12/20; size 409 bytes MD5 checksum 786366c9c8962af2a9d3e1cf3284d69c Compiled from "Hello.java" class Hello SourceFile: "Hello.java" minor version: 0 major version: 52 flags: ACC_SUPER Constant pool: #1 = Methodref #6.#15 // java/lang/Object."<init>":()V #2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #18 // hello #4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #21 // Hello #6 = Class #22 // java/lang/Object

アクセス許可やクラスの属性

コンスタントプール

参考: Table 4.1-A. Class access and property modifiers

Page 16: Javaクラスファイルの読み方

16

{ Hello(); descriptor: ()V flags: Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0

自動生成されたデフォルトコンストラクタフィールドやメソッドの型

自動生成されたreturn文

Javaプログラムの行番号

バイトコードのindex

コンスタントプールのエントリへの参照

Page 17: Javaクラスファイルの読み方

17

public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String hello 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 3: 0 line 4: 8 }

バイトコードのindexは,メソッドごとに0から始まる

…mainメソッド

Page 18: Javaクラスファイルの読み方

参考: 仮想マシン命令セット

18

参照: 「Chapter 6. The Java Virtual Machine Instruction Set」JVM仕様の目次をニーモニックでページ検索するとよいでしょう

0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String hello 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

getstatic: クラスのstaticフィールドの参照 ここではSystem.outインスタンスを取得する ldc: ランタイムからアイテムをpushする ここではhelloという文字列をpushする invokevirtual: インスタンスメソッドの呼び出し ここではPrintStream.printlnを呼び出す

ニーモニック

Page 19: Javaクラスファイルの読み方

javapの便利オプション(基本)

19

-private

-c

-l(小文字のL)

すべてのアクセス制御子のコードを表示するデフォルトではpulicとprotectedとdefaultだけ

行とローカル変数テーブルを表示する

逆アセンブルされたコードを表示する

Page 20: Javaクラスファイルの読み方

参考: local variable table

20

Javaが動作する時,各スレッドがスタックを持つ

ローカル変数の配列

オペランドスタック

参照

コンスタントプール

Page 21: Javaクラスファイルの読み方

javapの便利オプション(その他)

21

-classpathカレントディレクトリからCLASSPATHへの相対or絶対パスを指定する

逆アセンブルしたいクラス名は特定しているが,それがどのjarに含まれているか不明な時に便利

Page 22: Javaクラスファイルの読み方

classファイルフォーマット の読み方

22

Page 23: Javaクラスファイルの読み方

Javaのコンパイルと実行(再掲)

23

ハードウェア

OS OS OS

ハードウェア ハードウェア

JVM JVM JVM

中間コード 中間コード 中間コード

プラットフォーム共通

.class .class .class

中間コード.class

Javaプログラム

.java コンパイル

実行

Page 24: Javaクラスファイルの読み方

classファイルとは

24

中間コード.class

classファイルは8ビットのバイト・ストリームから 成り立っている.

値が意味を持つ最小構成単位が8ビットという意味

コンパイルによって生成されるファイル中間コード,中間ファイルとも呼ぶ

11001010111111101011101010111110

Java仮想マシン仕様 第2版

8 8 8 8

Page 25: Javaクラスファイルの読み方

JVM仕様書

25

Java Language and Virtual Machine Specificationshttps://docs.oracle.com/javase/specs/

上記の「Chapter 4. The class File Format」を参照します

Hello.classをバイナリエディタで開いてください

Page 26: Javaクラスファイルの読み方

26

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

参照: 4.1. The ClassFile Structure

Page 27: Javaクラスファイルの読み方

27

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

全体は擬似構造体

型項目

符号なし 4バイト

クラスやインタフェースと1対1

可変長table

固定長配列

配列の要素数

Page 28: Javaクラスファイルの読み方

型(u1, u2, u4)

28

1バイト=8ビットなので, u4型の項目は,8 * 4 = 32バイトで表現される

u1: 符号なし1バイト u2: 符号なし2バイト u4: 符号なし4バイト

Page 29: Javaクラスファイルの読み方

29

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

magic

Page 30: Javaクラスファイルの読み方

magic

30

110010101111111010111010101111108 8 8 8

C A F E B A B E

• Java classファイルを識別するための定数値 • 固定で16進数「CAFEBABE」 • u4型なので,次のように4バイト読む • 以降の項目も,固定長の場合は同じように読む

参照: http://radio-weblogs.com/0100490/2003/01/28.html

Page 31: Javaクラスファイルの読み方

31

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

minor_version, major_version

classファイルフォーマットのバージョン

Page 32: Javaクラスファイルの読み方

32

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

constant_pool_countconstant_poolテーブルの要素より1多い数字

Page 33: Javaクラスファイルの読み方

33

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

cp_info

Page 34: Javaクラスファイルの読み方

constant_pool[constant_pool_count-1]

34

• 可変長のtable • constant_pool_count-1個の要素数を持つ

• 中身を読まなければ,全体が何バイトあるかは分からない !

• 個々の要素は,javapの出力で「#n」というインデックスで参照されていた

Page 35: Javaクラスファイルの読み方

cp_info

35

cp_info { u1 tag; u1 info[]; } 参照: 4.4. The Constant Pool

constant_poolテーブルには,上のような構造のデータが要素数分だけ入っている

1つめの項目であるtagによって構造が異なる参照: Table 4.4-A. Constant pool tags

constant_poolcp_info

Page 36: Javaクラスファイルの読み方

36

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

access_flags

Page 37: Javaクラスファイルの読み方

access_flags

37

• アクセス許可やクラスの属性を表わす • javapにも出力されていた項目

!

• 和訳書籍の『JVMマシン仕様 第2版』ではaccess_flagsは5種類しか載っていませんが,これはJava1.2の頃の仕様で,現在は8種類です参考: Table 4.1-A. Class access and property modifiers

Page 38: Javaクラスファイルの読み方

38

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

this_class, super_class

Page 39: Javaクラスファイルの読み方

this_class, super_class

39

• this_class:constant_poolテーブルへのインデックスインデックス先はConstant_Class_info構造体

• super_class: constant_poolテーブルへのインデックスか,0 (Object classのときだけ0)インデックス先はConstant_Class_info構造体

Page 40: Javaクラスファイルの読み方

40

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

interfaces_count, interfaces[interfaces_count]

Page 41: Javaクラスファイルの読み方

interfaces_count, interfaces[interfaces_count]

41

• interfaces_count: このクラス,あるいはインタフェースの直接のsuper intarfaceの数

• interfaces[interfaces_count]: interfaces_count個の要素を持つ配列(固定長)

Page 42: Javaクラスファイルの読み方

42

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

fields_count, fields[fields_count]

Page 43: Javaクラスファイルの読み方

fields_count, fields[fields_count]

43

• fields_count:このクラス,あるいはインタフェースで定義されているフィールドの数

• fields[fields_count]: fields_count個の要素を持つfield_info構造体のテーブル(可変長)

Page 44: Javaクラスファイルの読み方

44

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

methods_count, methods[methods_count]

Page 45: Javaクラスファイルの読み方

methods_count, methods[methods_count]

45

• methods_count: このクラス,あるいはインタフェースで宣言されているメソッドの数(プログラム中に定義していない自動生成されたメソッドも含む)

• methods[methods_count]: methods_count個の要素を持つmethod_info構造体のテーブル(可変長)

Page 46: Javaクラスファイルの読み方

46

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

attributes_count, attributes[attributes_count]

Page 47: Javaクラスファイルの読み方

attributes_count,attributes[attributes_count]

47

• attributes_count:attribute_info構造体の数

• attributes[attributes_count]: attributes_count個の要素を持つattribute_info構造体のテーブル(可変長)

新たなattributeを定義できるのが特徴 Javaの言語機能が増えるとattribute_info構造体の種類が増える

Page 48: Javaクラスファイルの読み方

まとめ

48

• JVM仕様とは,「入力であるクラスファイルのデータ構造と出力である振る舞いのルールを定義するもの」 !

• javapは,classファイルのバイナリをJVM仕様とマッピングして表示してくれるツール

!

• classファイルフォーマットの表記ルールと読み進め方

Page 49: Javaクラスファイルの読み方

参考資料

49

Java Language and Virtual Machine Specificationshttps://docs.oracle.com/javase/specs/

http://d.hatena.ne.jp/torazuka/20120820/cafebabeJavaのクラスファイルの読み方

http://dev.classmethod.jp/server-side/java/classfile-reading/

Javaのクラスファイルをjavapとバイナリエディタで読む(このセッションのフォローアップ記事です)