android linker (1) —— __linker_init()
ilocker:關注 Android 安全(新手) QQ: 2597294287
__linker_init() 在 begin.S 中被調用,并傳入兩個參數:sp(堆棧指針)、#0。
linker(動態鏈接器,也稱解釋器)本身也是一個 shared object,__linker_init() 負責初始化 linker,完成 linker 的重定位等工作。由于在調用 __linker_init() 之前,linker 的重定位還沒有完成(GOT還不可用),所以任何對外部變量或函數的引用都會產生 segfault。
由于 linker 的重定位由其自己完成,所以該過程稱為 bootstrap(自舉)。
__linker_init() 的第一步是分解參數,把由 sp 參數傳入的 argc、argv、環境變量、ELF aux vectors 分別裝入KernelArgumentBlock 對象的相應成員中,方便訪問。
在 auxv 數組中,類型為 AT_BASE 的項存儲有 linker 鏡像的開始地址。__linker_init() 由此得到 linker_addr,繼而得到 elf_hdr(elf header) 和 phdr(program header) 的地址。
__linker_init() 接著填充一個 soinfo 結構變量。
成員 flags 設置上 FLAG_LINKER,后面見此標記就不會打印調試信息,因為那些調試函數在 linker 完成重定位前尚不可用。
phdr_table_get_load_size() 計算整個 linker 鏡像的大小,方法是根據 program header ,找到段內存的最大地址和最小地址,在完成頁對齊之后相減。
get_elf_exec_load_bias() 得到 linker 在內存中的加載地址,實際上是第一個可加載段(PT_LOAD)在內存中的虛擬地址。
上面描述有誤,get_elf_exec_load_bias() 只是計算第一個 LOAD 段在文件中的偏移 p_offset 與其在內存中的偏移 p_vaddr 的一個差值,然后再加上該 elf文件在內存中的基址。在后面使用時,比如從 LOAD 段里找 .dynamic 時:*dynamic=reinterpret_cast<ElfW(Dyn)*>(load_bias+phdr->p_vaddr);,只需要由 load_bias 加上 .dynamic 的 p_vaddr 就能得到 .dynamic 在內存中的虛擬地址了。
__linker_init() 接著以 linker_so 作為參數,調用 soinfo_link_image()。
在 soinfo_link_image() 中先找到動態鏈接段(PT_DYNAMIC)的地址,并得到動態鏈接結構的數量。然后遍歷所有動態鏈接結構,獲取諸如“字符串表地址”、“符號表地址”、“重定位表地址”等重要信息,填充到 soinfo 結構的相應成員中。接著加載所有依賴庫,但其實在 linker 自舉過程中,它并不依賴于任何其他shared object。重定位工作也是在 soinfo_link_image() 中完成,包括 rel 和 plt_rel(與 PLT 關聯的重定位項)。
__linker_init() 最后調用 __linker_init_post_relocation(),從名字可以看出,那些需要在重定位之后才能進行的工作都在這個函數中完成。
__linker_init() 最后返回鏡像的入口地址,也就是 elf header 中的 e_entry 保存的虛擬地址。
ilocker:關注 Android 安全(新手) QQ: 2597294287
總結
以上是生活随笔為你收集整理的android linker (1) —— __linker_init()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AndroidStudio-使用Tran
- 下一篇: 网页图标 favicon.ico 的引入