小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Kitkat系列文章—OAT文件分析—Part2

 老匹夫 2014-02-22

Kitkat系列文章—OAT文件分析—Part2

分享到: 1


本文由 ImportNew - Peter Pan 翻譯自 google。如需轉(zhuǎn)載本文,請先參見文章末尾處的轉(zhuǎn)載要求。

這是關(guān)于最新Android版本Kitkat系列文章中的第二部分,我把它們寫在了+inovex GmbH上。在這一部分,我們將進一步查看這種新的文件格式:ART運行時的OAT,并且簡要看一下它的垃圾回收機制(可以在這查看第一部分)。

3、進一步挖掘:OAT文件分析

目前為止我們發(fā)現(xiàn)系統(tǒng)在設(shè)備上執(zhí)行了一些編譯。不僅是應(yīng)用,而且還有Android框架層的很大一部分被ART轉(zhuǎn)化成了oat文件。在這篇文章中,我們會努力找出oat到底是什么東西以及oat文件是如何生成的。

正如前提到的,所有已安裝應(yīng)用通過dex2oat編譯從而得已運行?,F(xiàn)在讓我們進一步查看一下這些生成的文件。那么,讓我們通過adb分析dex2oat后的一個結(jié)果,例如這個由SystemUI.apk轉(zhuǎn)化后的結(jié)果:

1
/data/dalvik-cache/system@priv-app@SystemUI.apk@classes.dex

便捷的“file”命令會返回:

1
2
3
4
5
6
7
8
9
10
11
12
system@priv-app@SystemUI.apk@classes.dex: ELF 32-bit LSB shared object, ARM, version 1 (GNU/Linux), dynamically linked, stripped
Wow.. that escalated quickly! With ART we go from java -> class -> dex -> oat, which is a shared object!
Further analysis with objdump shows the following:
system@priv-app@SystemUI.apk@classes.dex:
file format elf32-little
DYNAMIC SYMBOL TABLE:
00001000 g DO .rodata 0007d000 oatdata
0007e000 g DO .text 000a9f8f oatexec
00127f8b g DO .text 00000004 oatlastword

這里只確定了三個標(biāo)識:元數(shù)據(jù)、執(zhí)行的起始與終止地址。很明顯的,新的運行時把應(yīng)用當(dāng)作共享對象來進行處理(!)。共享對象被動態(tài)加載到虛擬機的上下文(很可能是先前解釋過的啟動鏡像)中。通過查看源可以知道:實際上在運行時調(diào)動dlopen()來加載這些庫。

現(xiàn)在讓我們使用新的oatdump來獲取更多關(guān)于oat文件格式的知識。我的首次嘗試是在啟動鏡像文件“/data/dalvik-cache/system@framework@boot.art@classes.dex”中使用oatdump。但是結(jié)果顯示這個文件的整個dump文件有1.6GB大小,這對于我將嘗試的這種分析而言是十分不方便,
所以我寫了一個小程序,雖然幾乎談不上有什么具體的功能,但是卻簡單到足以理解這個OAT是如何工作的。源代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package de.inovex.arttest;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int a = 100;
        a = foo(a);
    }
    private int foo(int a) {
        return a + 4711;
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

安裝之后,我們能夠在主機上查看它的編譯版本并在其上執(zhí)行objdump:

1
2
3
4
5
6
data@app@de.inovex.arttest.apk@classes.dex: file format elf32-little
DYNAMIC SYMBOL TABLE:
00001000 g DO .rodata 00001000 oatdata
00002000 g DO .text 00000238 oatexec
00002234 g DO .text 00000004 oatlastword

目前而言沒什么驚喜…它顯然是一個幾乎沒有任何功能、有0×238字節(jié)的應(yīng)用程序;-)

所以,讓我在文件”oatdump –oat-file= data@app@de.inovex.arttest.apk@classes.dex”上使用oatdump:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MAGIC:
oat
007
CHECKSUM:
0x7fcf3941
INSTRUCTION SET:
Thumb2
DEX FILE COUNT:
1
EXECUTABLE OFFSET:
0x00001000
IMAGE FILE LOCATION OAT CHECKSUM:
0xd950003d
IMAGE FILE LOCATION OAT BEGIN:
0x60a95000
...

這個header向我們展示了一些信息,包括文件內(nèi)容、體系結(jié)構(gòu)、一些完整性檢測值和一些想必是用來正確地移動該庫的地址。有意思的部分在于這個dump輸出體中的方法名、dex碼和這個方法的ARM拆解碼。例如:foo方法的oat-dump輸出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1: int de.inovex.arttest.MainActivity.foo(int) (dex_method_idx=5)
DEX CODE:
0x0000: add-int/lit16 v0, v2, #+4711
0x0002: return v0
OAT DATA:
frame_size_in_bytes: 32
core_spill_mask: 0x00008060 (r5, r6, r15)
fp_spill_mask: 0x00000000
vmap_table: 0xf73b00da (offset=0x000010da)
v0/r5, v2/r6, v65535/r15
mapping_table: 0xf73b00d8 (offset=0x000010d8)
gc_map: 0xf73b00e0 (offset=0x000010e0)
CODE: 0xf73b00bd (offset=0x000010bd size=28)...
0xf73b00bc: e92d4060 push {r5, r6, lr}
0xf73b00c0: b085 sub sp, sp, #20
0xf73b00c2: 9000 str r0, [sp, #0]
0xf73b00c4: 9109 str r1, [sp, #36]
0xf73b00c6: 1c16 mov r6, r2
0xf73b00c8: f2412267 movw r2, #4711
0xf73b00cc: eb160502 adds.w r5, r6, r2
0xf73b00d0: 1c28 mov r0, r5
0xf73b00d2: b005 add sp, sp, #20
0xf73b00d4: e8bd8060 pop {r5, r6, pc}

DEXCODE部分體現(xiàn)的信息十分明顯:Java源碼中的整型a映射到虛擬寄存器v2中,加上常量4711,然后在v0上存儲結(jié)果并返回。

OAT DATA還沒完全被處理,但明顯的是“core_spill_mask”描述了被用在那個ARM方法里面?zhèn)鬟f數(shù)據(jù)的寄存器,“vmap_table”顯示出虛擬寄存器與真實寄存器的映射關(guān)系。

CODE區(qū)域顯示處理器事實上將要執(zhí)行的東西:起初,r2持有整型a;在新的棧楨創(chuàng)建之后,常量4711回到家整型a上;之后,結(jié)果被傳回來。然見到這些雖然不是驚喜,但也令人印象深刻!

同時還提示:上述過程中幾乎沒有任何優(yōu)化,更像是一個“gcc-00”。顯然不需要新的棧楨,整個“計算”通過單獨的一條指令完成:adds.w r0, r2, #4711。

最后,讓我們來總結(jié)一下OAT文件是什么:OAT是類似APK的一種預(yù)編譯文件,像共享庫一樣被正在運行的進程加載。OAT包含了APK中所有類的信息,比如方法、方法名、描述信息和偏移列表,可以在二進制中定位這些方法。

4、留意堆處理:ART中的GC

ATR中的垃圾回收機制跟Dalvik極其相似,兩者都采用“標(biāo)記—清除”的方式保持堆清潔。詐一看令人十分驚奇,但事實上卻十分容易理解。從Java源碼,到類、dex,再到機器碼都可以追蹤。盡管代碼執(zhí)行的方式已經(jīng)改變,但數(shù)據(jù)結(jié)構(gòu)和對象引用卻依然保持不變。因此,垃圾回收進程可以用Dalvik相同的方式進行回收。

對源art/runtime/gc的簡單了解可以發(fā)現(xiàn)ART使用了4種不同類型的GC。它們可以并行,也可以被列舉出來釋放堆空間:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// The type of collection to be performed. The ordering of the enum matters, it
// is used to
// determine which GCs are run first.
enum GcType {
    // Placeholder for when no GC has been performed.
    kGcTypeNone,
    // Sticky mark bits GC that attempts to only free objects allocated since
    // the last GC.
    kGcTypeSticky,
    // Partial GC that marks the application heap but not the Zygote.
    kGcTypePartial,
    // Full GC that marks and frees in both the application and Zygote heap.
    kGcTypeFull,
    // Number of different GC types.
    kGcTypeMax,
};

GC通過上面枚舉的次序進行循環(huán),直到有足夠可用的空間來分配需要的內(nèi)存:

1
2
3
4
art/runtime/gc/heap.cc
// Loop through our different Gc types and try to Gc until we get enough free memory.
for (size_t i = static_cast<size_t>(last_gc) + 1;
i < static_cast<size_t>(collector::kGcTypeMax); ++i) {...

如果這個程序失敗了,系統(tǒng)會通過增大堆空間等方式再次嘗試分配。但這完全是一個標(biāo)準(zhǔn)程序,沒有任何不同于Dalvik垃圾回收的地方,至少我沒有發(fā)現(xiàn)。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多