More Related Content
Similar to Dalvikバイトコードリファレンスの読み方 改訂版
Similar to Dalvikバイトコードリファレンスの読み方 改訂版 (20)
More from Takuya Matsunaga
More from Takuya Matsunaga (8)
Dalvikバイトコードリファレンスの読み方 改訂版
- 2. 自己紹介
上での活動
Web上での活動
・ハンドルネーム : kmt-t
・はてなダイアリ ID : kmt-t2
・Twitter ID : kmt_t
属性
属性
・鳥取県から大阪に出稼ぎ中です
・組み込みプログラマらしい
・組み込みプログラマらしい
・ミドルウェアが得意です
・ミドルウェアが得意です
→画像処理(2D/3D)、ファイルシステム、仮想マシンが専門です
→画像処理(2D/3D)、ファイルシステム、仮想マシンが専門です
・使用言語はC++(not C)/C#/Python
・使用言語はC++(not C)/C#/Python
→C++11とかC#の最新の仕様がキャッチアップできていません
→C++11とかC#の最新の仕様がキャッチアップできていません
- 3. 発表の構成
仮想マシン3部作
Dalvik仮想マシン 部作
仮想マシン
Dalvik仮想マシンの発表を以下の3回にわけて行います
1. Dalvik仮想マシンのアーキテクチャ
2. Dalvikバイトコードのリファレンスの読み方 ←今回はここの発表
バイトコードのリファレンスの読み方
3. DEXファイルフォーマット
発表の目的
仮想マシンのソースコードが誰でも読めるようにする
1. Dalvik仮想マシンのソースコードが誰でも読めるようにする
仮想マシンに対するみんなのリテラシを上げる
2. Dalvik仮想マシンに対するみんなのリテラシを上げる
3. より深い部分の発表をするための下地をつくる
- 4. 本日の発表の概要
バイトコードリファレンスの読み方
Dalvikバイトコードリファレンスの読み方
・Dalvikバイトコードの命令バイナリフォーマット
・Dalvikバイトコード命令に対応する実装
→リファレンスから実装をトレースできるように
リファレンスから実装をトレースできるように
リファレンス
・dalvik/docs/dalvik-bytecode.html (概略リファレンス ←注目
概略リファレンス)
概略リファレンス
・dalvik/docs/instruction-formats.html (バイナリフォーマット)
・dalvik/docs/opcodeディレクトリ以下 (セマンティクス)
実装
今回はC言語バージョンの実装を参照
・dalvik/vm/mterp/out/InterpC-portstd.c
- 6. 記述されている内容
表の列
注目する章の表には以下の列がある
・Op & Format
→命令のオペコードとバイナリフォーマット
・Mnemonic / Syntax
→命令のオペランドとそのサイズと並び
・Arguments
→オペランド一覧
・Description
→命令の概要
- 7. Op & Format
列の意味
・「01 12x」とは何か?
→「01」は命令のオペコード (16進数)
→「12x」は命令のバイナリフォーマットID
・命令のバイナリフォーマットの詳細
→この命令の場合は命令のバイナリフォーマットIDは「12x」
→dalvik/docs/instruction-formats.htmlの対応する行を参照
- 8. Mnemonic / Syntax
列の意味
・「move vA, vB」とは何か?
→「move」は命令の名前
→「vA」、「vB」はオペランドにレジスタ番号「A」、「B」を持つことを示す
・レジスタ番号の表記は「vA」、「vAA」、「vAAAA」のバリエーションを持つ
→「vA」の場合4bit幅のレジスタ番号(0~15)を持つ
→「vAA」の場合8bit幅のレジスタ番号(0~255)を持つ
→「vAAAA」の場合16bit幅のレジスタ番号(0~65535)を持つ
→レジスタ番号MAX値65535にアクセスできない命令がほとんど
- 9. Arguments
列の意味
・オペランドとしてレジスタAとレジスタBを持つ
・レジスタAはデストネーションレジスタ (レジスタ番号は4bit幅)
・レジスタAはソースレジスタ(レジスタ番号は4bit幅)
- 10. Description
列の意味
命令の概要
→「オブジェクトではないレジスタの内容を他のレジスタにコピーする」
→命令ごとの覚書が書かれている
→命令の挙動はあまり書かれていない場合も多い
→詳細はdalvik/docs/opcodeディレクトリ以下参照
- 20. バイトコード命令の実装を読む
invoke-virtual命令の例 (2)
対応する実装
・dalvik/vm/mterp/out/InterpC-portstd.c
・GOTO_TARGET(invokeVirtual, bool methodCallRange)
処理内容
1. 引数の数を命令から取得
2. メソッドIDを命令から取得
3. メソッド引数のレジスタ番号を命令から取得
4. クラスインスタンスポインタのNULLチェック
5. メソッドIDから基底メソッドの「Method構造体
構造体※1」 を取得
構造体
5.1. クラスIDとメソッドIDの組をキーにキャッシュを取得
5.2. キャッシュミスの場合はDEXファイルを検索して取得
6. 基底メソッドのMethod構造体からメソッドのvtableインデックスを取得
- 21. バイトコード命令の実装を読む
invoke-virtual命令の例 (3)
続き)
処理内容 (続き
続き
7. 派生メソッドのMethod構造体をクラスインスタンスのvtableから取得
8. 抽象メソッドの呼び出しでないかチェック
9. 引数レジスタの値をひとつずつ取り出しスタックに積む
10. 新しいフレームポインタを計算
11. 「vm-specific-internal-goop※2」の位置を計算
12. スタックあふれが発生していないかチェック
13. vm-specific-internal-goopにメソッド呼び出し元情報を保存
フレームポインタ※3」を保存
13.1. 呼び出し元の「フレームポインタ
フレームポインタ
13.2. 呼び出し元の「プログラムカウンタ
プログラムカウンタ※4」を保存
プログラムカウンタ
13.3. 現在のメソッド情報構造体のポインタを保存
- 22. バイトコード命令の実装を読む
invoke-virtual命令の例 (4)
続き)
処理内容 (続き
続き
14. (以下ネイティブメソッドでない場合)
15. 「InterpSaveState構造体
構造体※4」の書き換え
構造体
15.1. 実行中のメソッドを呼び出し側に変更
15.2. プログラムカウンタを呼び出し先のものに変更
15.3. フレームポインタを呼び出し先のものに変更
- 23. バイトコード命令の実装を読む
invoke-virtual命令の例 (5)
構造体
Method構造体
仮想マシンの実行に必要なメソッドの情報を保存する構造体
struct Method {
ClassObject* clazz; // 所属するクラス
u4 accessFlags; // アクセス権限フラグ
u2 methodIndex; // vtableのインデックス
u2 registersSize; // レジスタ数
u2 outsSize; // 出力引数の数
u2 insSize; // バイトコード長 (16bit単位)
const char* name; // メソッド名
DexProto prototype; // メソッドの型
const char* shorty; // メソッドの型(文字列形式)
const u2* insns; // バイトコードのポインタ
// 以下省略
};
- 26. バイトコード命令の実装を読む
invoke-virtual命令の例 (7)
構造体
InterpSaveState構造体
実行中の仮想マシンの状態を保存する構造体
struct InterpSaveState {
const u2* pc; // 現在実行中のバイトコード命令のポインタ
u4* curFrame; // 現在のフレームポインタ
const Method *method; // 現在のメソッド
DvmDex* methodClassDex; // 現在のメソッドが格納されているDEXファイル
JValue retval; // メソッドの戻り値を格納する領域
void* bailPtr; // インタープリタの開始点に戻るためのポインタ
struct InterpSaveState* prev; // To follow nested activations
} __attribute__ ((__packed__));
- 27. まとめ
まとめ
・バイトコードリファレンスの読み方はパターンがある
・バイトコードリファレンスを起点にして実装を読むと楽である
以上でバイトコードリファレンスが読めるようになり、かなり実装も追える
ようになるはず!