Android Prelink實現的原始碼分析

2021-06-25 08:56:13 字數 3041 閱讀 4326

1. 原理簡介

1) prelink

prelink即預鏈結技術是利用事先鏈結以代替執行時鏈結的技術,以加快共享庫的載入速度,它不僅能加快程式啟動時間,還可以減少部分記憶體開銷(它能使kde的啟動時間減少50%)。每次程式執行時,進行的鏈結動作都是一樣的,鏈結相對來說開銷很大,尤其是嵌入式系統。

2) 普通linux系統的prelink

redhat系統中prelink工具(/etc/cron.dialy/prelink)會修改可執行程式,把它與所需庫的鏈結資訊加入可執行程式。在程式執行時,使用glibc(glibc > 2.3.1-r2)中的ld-linux.so來進行鏈結。用此方式,每次更新動態庫後,使用它的程式都需要重新prelink,因為新庫中的符號資訊,位址等很可能與原來不同了。

3) android的prelink

android原始碼中有一組map檔案,其中定義了需要預連線的動態庫,其prelink資訊以及對應的邏輯位址(4g位址空間中位置),在動態庫編譯時,預處理程式apriori根據map檔案中的定義,生成預鏈結資訊重定向資訊,並加入到這些二進位制檔案lib*.so的末尾。它主要節約了查詢函式位址等工作所用的時間,動態庫重定位的開銷。在執行程式,動態庫載入時,引導程式linker判斷動態庫是否為prelink的,如果是的話,就在首次使用時將其載入到指定的記憶體空間,直接使用預編譯資訊。

2. 原始碼分析

1)  動態庫的編譯指令碼

a) 源**

frameworks/base/media/libmedia/android.mk等庫的編譯選項檔案

b) 配置

可在android.mk中設定該庫是否需要prelink,預設是使用prelink的,也可設定成否,方法如下:

local_prelink_module := false

c) 分析

此設定只用於動態庫的編譯,編譯時用showcommands引數即可看到具體編譯使用到的命令列,如在某個庫的目錄中執行mm showcommands,即可看到相應的prelink操作,示例如下:

target prelink: lib***

out/host/linux-x86/bin/apriori --prelinkmap build/core/prelink-linux-arm-2g.map --locals-only --quiet ***.so --output ***.so

如果該庫設定為需要prelink,則也需要在map檔案中加入相應項,否則編譯不通過

2) 核心

a) 原始碼

kernel/arch/arm/configs/***_defconfig

arch/arm/mach-msm/include/mach/vmalloc.h

b) 配置

config_vmsplit_2g=y一般預設為3g/1g,此項即設定為2g/2g

c) 分析

***_defconfig為預設的核心配置檔案(修改其中的config_vmsplit_*),也可通過make menuconfig配置,與prelink相關的主要是指定使用者空間和核心空間記憶體如何分配4g的虛擬記憶體空間(memory split),一般有三種方式:3g/1g,2g/2g,1g/3g(user/kernel),一般預設的是使用者空間3g(0x0-0xbfffffff),核心空間1g(0xc0000000 - 0xffffffff)

3) map檔案

a) 源**

build/core/prelink-linux-*.map

b) 配置

編譯時有多個map檔案可選,根據不同的硬體平台及記憶體分配(3g/1g, 2g/2g)修改系統配置deviceboardconfig.mk中設定

target_uses_2g_vm_split := true 以配置prelink的位址空間

c) 分析

apriori中的prelinkmap.c它用根據整個系統設定device/*/boardconfig.mk的記憶體分配規則(3g/1g, 2g/2g)來判斷map中指定位址是否符合prelink的位址空間範圍,如果正常,則在so的末尾加入prelink資訊和標識(檔案以pre結束)

apriori可以預先為若干共享庫確定載入位址,並為有依賴關係的共享庫做靜態重定位和連線, 該命令加入引數--verbose,即可顯示出prelink的細節。

5) linker程式

a) 源**

bionic/linker/*

(bionic目錄中存放一些基礎的庫,如libc, libstdc++, libthread_db, linker等)

b) 分析

linker是android的專用動態鏈結庫鍵接器,linker和傳統linux使用的linker(ld.so,ld-linux.so.2,ld-linux.so.3)有所不同。庫的編譯引數-dynamic-linker指定了鍵接器為/system/bin/linker(也可以手動換成別的),該資訊將被存放在elf檔案的.interp節中,核心執行目標映像檔案前將通過該資訊載入並執行相應的直譯器程式linker,並鏈結相應的共享庫,共享庫以elf檔案的形式儲存在檔案系統中。核心的load_elf_binary會首先將其映像檔案對映到記憶體,然後對映並執行其直譯器也就是linker的**。linker的**段是程序間共享的,但資料段為各程序私有。

所有外部過程引用都在映像執行之前解析, android中的共享庫和可執行映像都預設採用elf格式的檔案. 程式頭表包含了載入到記憶體中的各種段的索引及屬性資訊,它將告訴載入器如何載入映像,初始化時,動態鏈結器首先解析出外部過程引用的絕對位址,一次性的修改所有相應的got表項。

linker會在共享庫載入時,呼叫is_prelinked檢視該庫是否是prelink的,並在alloc_mem_region中檢查目的位址是否被占用。如果該庫不是prelink的,則庫載入的起始位址為零。

3. 參考文件:

1) 動態庫優化——prelink(預連線)技術

2)  android build system note - 一醉千年 - csdn部落格

3)  linux, android基礎知識總結

4)  android linker**

**:

實變函式 實分析總結

一 概述。實變函式,又叫實分析,整本書滿滿的證明就講了乙個勒貝格積分。最為大家所熟知的是用牛頓 萊布尼茨公式算的黎曼積分。但是黎曼積分本身依賴於函式的連續性,像不連續的狄利克雷函式就無法積分了。為了解決這一問題,勒貝格利用分割值域的方法,使得函式可積。但是分割出來的值域,只能放在一起,形式集合。如果...

NestedScrollWebview實現與優化

nestedscrollwebview實現與優化 原文如下 好久沒寫了,好像也沒什麼人關注我,呵呵,但我還是堅持寫一下,希望能幫到有需要的人!今天我來說一下nestedscrollwebview。最近在弄乙個需求,我需要用到coordinatorlayout webview 實現滾動互動效果,但要實...

saltstack keepalived實現高可用

本篇部落格承接saltstack安裝部署和saltstack grains,pillar,jinja模組的使用 建立目錄。root server1 keepalived vim files keepalived.conf configuration file for keepalived globa...