基於android2.3.5系統:Android動態庫連結

來源:互聯網
上載者:User

***************************************************************************************************************************
作者:EasyWave                                                                                 時間:2013.03.24

類別:Android系統源碼分析                                                              聲明:轉載,請保留連結

注意:如有錯誤,歡迎指正。這些是我學習的日誌文章......

***************************************************************************************************************************

跟普通的linux基本一樣,不過android是採用了自己的glibc,也就是在bionic這個檔案中,在這個檔案夾中它有libc、libdl、libm、libstdc++、libthread_db以及linker,如所示:

1):libc

libc是Android下的C的函數庫。
bionic libc是基本的C語言函數庫,包含了C語言最基本的庫函數。這個庫可以根據 標頭檔劃分為 幾個 個部分,包括:字元類型、錯誤碼、 浮點常數、數學常數、標準定義 、 標準 I/O、工具函數、字串操作 等等。如所示:

2):libdl
這個一個跟動態庫連結有關的一個庫,也就是說,所有libxxx.so都是由它來開啟。它提供了如下的函數供應用開發人員動態開啟和載入動態庫,如下:

void *dlopen(const char *filename, int flag) { return 0; }const char *dlerror(void) { return 0; }void *dlsym(void *handle, const char *symbol) { return 0; }int dladdr(void *addr, Dl_info *info) { return 0; }int dlclose(void *handle) { return 0; }

不過需要注意的是,上面函數的具體實現,卻是在bionic/linker/Dlfcn.c中實現的。如下所示:

3):libm

這個是andriod下的標準數學庫

4):libstdc++

這個是G++相關的庫

5):libthread_db

這是跟線程相關的庫函數。

6):linker

linker 主要用於實現共用庫的載入與連結。它支援應用程式對庫函數的隱式和顯式調用。對於隱式調用,應用程式的編譯與靜態庫大致相同,只是在靜態連結的時候通過--dynamic-linker /system/bin/linker 指定動態連結器,(該資訊將被存放在ELF檔案的.interp節中,核心執行目標映像檔案前將通過該資訊載入並運行相應的解譯器程式linker.)並連結相應的共用庫。與ld.so不同的是,Linker目前沒有提供Lazy
Binding機制,所有外部過程引用都在映像執行之前解析。對於顯式調用,可以同過linker中提供的介面dlopen,dlsym,dlerror和dlclose來動態載入和連結共用庫。

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

Android的Prelink的機制:
Android源碼中有一組map檔案,其中定義了需要預串連的動態庫,其Prelink資訊以及對應的邏輯地址(4G地址空間中位置),在動態庫編譯時間,預先處理程式apriori根據map檔案中的定義,產生預連結資訊重新導向資訊,並加入這些二進位檔案lib*.so的末尾。它主要節約了查詢函數地址等工作所用的時間,動態庫重定位的開銷。在運行程式,動態庫載入時,載入程式linker判斷動態庫是否為Prelink的,如果是的話,就在首次使用時將其載入到指定的記憶體空間,直接使用先行編譯資訊。如果要開啟prelinker的話,需要進行一些配置,在Android.mk中設定該庫是否需要Prelink,預設是使用Prelink的,也可設定成否,方法如下:
LOCAL_PRELINK_MODULE := false
在android中它是以build/core/prelink_linux_arm.map檔案為基礎,來分配動態庫的地址的,如下所示:

也就是說,如果想自己添加第三方動態庫的話,就需要在build/core/prelink-linux-arm.map 中加入形如libxxx.so 0xxx000000。
手工指定某個庫相應的prelink位址範圍,庫應用對齊1M邊界,注意庫與庫之間的間隔數,如果指定不好編譯的時候會提示說地址空間衝突的問題。另外,注意排序,這裡要把數大的放到前面去,按照大小降序排序。
而在andriod中,以apriori中的prelinkmap.c它用根據整個系統設定BoardConfig.mk的記憶體配置規則(3G/1G, 2G/2G)來判斷map中指定地址是否符合Prelink的地址空間範圍,如果正常,則在so的末尾加入prelink資訊和標識(檔案以PRE結束),apriori可以預先為若干共用庫確定載入地址,並為有依賴關係的共用庫做靜態重定位和串連, 該命令加入參數--verbose,即可顯示出prelink的細節。

以下為網路摘取:
       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的,則庫載入的起始地址為零。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.