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

  • 72 views
Uploaded on

2014年12月20日の「Javaクラスファイル入門」で説明に使った資料です。

2014年12月20日の「Javaクラスファイル入門」で説明に使った資料です。

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
72
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
0
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Javaクラスファイル   の読み⽅方 Javaクラスファイル⼊入⾨門   2014/12/20 初⼼心者向け 1
  • 2. このセッションの流れ 2 • JVM仕様とは何かについて • javapを使ってみましょう • classファイルフォーマットの読み方概要 • 後続セッションでの実践の準備 http://dev.classmethod.jp/server-side/java/classfile-reading/ 追記: このセッションのフォローアップ記事を書きました Javaのクラスファイルをjavapとバイナリエディタで読む
  • 3. Javaのコンパイルと実行 3 ハードウェア OS OS OS ハードウェア ハードウェア JVM JVM JVM 中間コード 中間コード 中間コード プラットフォーム共通 .class .class .class 中間コード .class Javaプログラム .java コンパイル 実行
  • 4. JVM 4 ハードウェア OS OS OS ハードウェア ハードウェア JVM JVM JVM 中間コード 中間コード 中間コード プラットフォーム共通 JVM プラットフォーム依存 .class .class .class
  • 5. JVM仕様とは 5 JVM仕様は,実装の詳細には踏み込まない 入力であるクラスファイルのデータ構造と 出力である振る舞いのルールを定義するもの このルールを満たす実装をJVMと呼ぶ 逆に言うと,特定のJVMの仕様を定めたものではない
  • 6. classファイル・フォーマットとは 6 Javaのクラスファイルを表現するバイナリの並びを
 定義したもの u4 magic u2 minor_version u2 major_version u2 constant_pool_cont など
  • 7. 2つのツールの違い 7 javap バイナリエディタ バイナリデータを読みやすく整形して表示する 入力として想定するのは,ファイルなら何でも バイナリデータをJavaのclassファイルとして解釈し,
 JVM仕様で定義されたデータ構造とのマッピングを表示する 入力として想定するのは,Java classファイルのみ どちらもバイナリデータを読み込む点は共通
  • 8. javap 8 Javaの標準ツール OpenJDKベースのJDKに入っている コマンドラインで実行する ターミナル,iTerm,コマンドプロンプト(Windows) Javaクラスファイルを逆アセンブルするために使う
  • 9. どんなときにjavapを使うか 9 • 複数のコンパイラを使う状況で,コンパイラごとに
 出力される中間コードの差分を見たいとき • 処理系を作る際に,期待する入力と実際の中間コード
 の差分を見たいとき バイナリとは異なる粒度でファイル間の差分を見る時に
 使うのではないかと思います そういった作業をしなければ使う機会はあまりないと思います (例)
  • 10. javapを使ってみましょう 10
  • 11. javapを使う前提条件 11 • Javaがインストールされていること • OpenJDK系のJDKがインストールされていること • JREだけでなく,JDKが必要です PCをお持ちでない方は,javapの出力内容の説明に入るまで
 少々お待ちください.
  • 12. 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
  • 13. javapの出力例 13 % javap Hello Compiled from "Hello.java" class Hello { Hello(); public static void main(java.lang.String[]); } 次のような出力が得られましたか? そのままでは情報量が少ないため,vオプションをつけて
 もう一度実行してください % javap -v Hello
  • 14. javapの出力例の説明 14 javapの出力は,JVM仕様を参照しながら
 バイナリを読めるようになった後の方が理解しやすい javapの出力はすでにJVM仕様とマッピングされているが,
 バイナリエディタを使って見る作業では自分でマッピングするため このタイミングで詳細が分からなくてもこだわらず, どんな項目が出力されるかを眺めておいてください どうしても気になる時は,JVM仕様内を検索してみてください (注意事項)
  • 15. 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 …
  • 16. 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 … … コンスタントプールのエントリへの参照
  • 17. 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メソッド
  • 18. 参考: 仮想マシン命令セット 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を呼び出す ニーモニック
  • 19. javapの便利オプション(基本) 19 -private -c -l(小文字のL) すべてのアクセス制御子のコードを表示する
 デフォルトではpulicとprotectedとdefaultだけ 行とローカル変数テーブルを表示する 逆アセンブルされたコードを表示する
  • 20. 参考: local variable table 20 Javaが動作する時,各スレッドがスタックを持つ ローカル変数の配列 オペランドスタック 参照 コンスタントプール
  • 21. javapの便利オプション(その他) 21 -classpath カレントディレクトリからCLASSPATHへの
 相対or絶対パスを指定する 逆アセンブルしたいクラス名は特定しているが,
 それがどのjarに含まれているか不明な時に便利
  • 22. classファイルフォーマット
 の読み方 22
  • 23. Javaのコンパイルと実行(再掲) 23 ハードウェア OS OS OS ハードウェア ハードウェア JVM JVM JVM 中間コード 中間コード 中間コード プラットフォーム共通 .class .class .class 中間コード .class Javaプログラム .java コンパイル 実行
  • 24. classファイルとは 24 中間コード .class classファイルは8ビットのバイト・ストリームから
 成り立っている. 値が意味を持つ最小構成単位が8ビットという意味 コンパイルによって生成されるファイル
 中間コード,中間ファイルとも呼ぶ 11001010111111101011101010111110 Java仮想マシン仕様 第2版 8 8 8 8
  • 25. JVM仕様書 25 Java Language and Virtual Machine Specifications https://docs.oracle.com/javase/specs/ 上記の「Chapter 4. The class File Format」を参照します Hello.classをバイナリエディタで開いてください
  • 26. 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
  • 27. 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 固定長配列 配列の要素数
  • 28. 型(u1, u2, u4) 28 1バイト=8ビットなので, u4型の項目は,8 * 4 = 32バイトで表現される u1: 符号なし1バイト u2: 符号なし2バイト u4: 符号なし4バイト
  • 29. 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
  • 30. magic 30 11001010111111101011101010111110 8 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
  • 31. 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ファイルフォーマットのバージョン
  • 32. 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_count constant_poolテーブルの要素より1多い数字
  • 33. 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
  • 34. constant_pool[constant_pool_count-1] 34 • 可変長のtable • constant_pool_count-1個の要素数を持つ • 中身を読まなければ,全体が何バイトあるかは
 分からない ! • 個々の要素は,javapの出力で「#n」という
 インデックスで参照されていた
  • 35. 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_pool cp_info
  • 36. 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
  • 37. access_flags 37 • アクセス許可やクラスの属性を表わす • javapにも出力されていた項目 ! • 和訳書籍の『JVMマシン仕様 第2版』では
 access_flagsは5種類しか載っていませんが,
 これはJava1.2の頃の仕様で,現在は8種類です 参考: Table 4.1-A. Class access and property modifiers
  • 38. 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
  • 39. this_class, super_class 39 • this_class:
 constant_poolテーブルへのインデックス
 インデックス先はConstant_Class_info構造体
 • super_class: 
 constant_poolテーブルへのインデックスか,0
 (Object classのときだけ0)
 インデックス先はConstant_Class_info構造体
  • 40. 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]
  • 41. interfaces_count,
 interfaces[interfaces_count] 41 • interfaces_count:
 このクラス,あるいはインタフェースの
 直接のsuper intarfaceの数
 • interfaces[interfaces_count]: 
 interfaces_count個の要素を持つ配列(固定長)
  • 42. 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]
  • 43. fields_count,
 fields[fields_count] 43 • fields_count:
 このクラス,あるいはインタフェースで定義されて
 いるフィールドの数
 • fields[fields_count]: 
 fields_count個の要素を持つfield_info構造体
 のテーブル(可変長)
  • 44. 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]
  • 45. methods_count,
 methods[methods_count] 45 • methods_count:
 このクラス,あるいはインタフェースで宣言されて
 いるメソッドの数
 (プログラム中に定義していない自動生成されたメソッドも含む)
 • methods[methods_count]: 
 methods_count個の要素を持つmethod_info
 構造体のテーブル(可変長)
  • 46. 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]
  • 47. attributes_count,
 attributes[attributes_count] 47 • attributes_count:
 attribute_info構造体の数
 • attributes[attributes_count]: 
 attributes_count個の要素を持つattribute_info
 構造体のテーブル(可変長) 新たなattributeを定義できるのが特徴 Javaの言語機能が増えるとattribute_info構造体の種類が増える
  • 48. まとめ 48 • JVM仕様とは,「入力であるクラスファイルの
 データ構造と出力である振る舞いのルールを
 定義するもの」 ! • javapは,classファイルのバイナリをJVM仕様と
 マッピングして表示してくれるツール ! • classファイルフォーマットの表記ルールと
 読み進め方
  • 49. 参考資料 49 Java Language and Virtual Machine Specifications https://docs.oracle.com/javase/specs/ http://d.hatena.ne.jp/torazuka/20120820/cafebabe Javaのクラスファイルの読み方 http://dev.classmethod.jp/server-side/java/classfile-reading/ Javaのクラスファイルをjavapとバイナリエディタで読む
 (このセッションのフォローアップ記事です)