Android C語言_init函數和constructor屬性及.init/.init_array節探索

來源:互聯網
上載者:User

標籤:開啟   exp   ext   程式   指標數組   方法   情況   lob   區別   

本篇文章主要介紹了"Android C語言_init函數和constructor屬性及.init/.init_array節探索",主要涉及到Android C語言_init函數和constructor屬性及.init/.init_array節探索方面的內容,對於Android C語言_init函數和constructor屬性及.init/.init_array節探索感興趣的同學可以參考一下。

瞭解C語言的程式猿都知道有兩種方法可以讓一部分代碼在so或可執行檔被載入的時候先於其它任何函數執行,一種是定義一個void _init(void)函數,另一種是在函數後面聲明constructor屬性。那麼這兩種方式在執行的時候有什麼區別嗎?先後順序呢?瞭解ELF檔案格式的人又會問它們在檔案中的位置又有什麼差別呢?這篇文章就來解答這些問題。

首先你需要瞭解一下ELF檔案格式了,這裡就不囉嗦了,不瞭解的人可以搜一下看看。

下面是一個例子,在你的Android工程中的C/C++代碼中加入下面幾行:

 

........#ifdef __cplusplusextern "C" {#endifvoid _init(void){mlog_info("_init enter");}#ifdef __cplusplus}#endifvoid __attribute__((constructor)) myConstructor(void){mlog_info("myConstructor enter\n");}........


我這邊編譯出來是libcheckcert.so檔案,放到手機上去啟動並執行結果是:

 

 

........12-13 11:04:46.603: I/BRIAN(12203): _init enter12-13 11:04:46.603: I/BRIAN(12203): myConstructor enter........

_init函數是最先啟動並執行,為什麼會這樣呢?瞭解ELF檔案的人都知道有.init和.init_array這兩個節,它們是ELF檔案在載入的時候用來做初始化的,那麼它們和_init函數及constructor屬性有什麼關係呢?下面我們需要藉助readelf和IDA pro來查看,首先readelf -d libcheckcert.so來查看ELF的dynamic段:

 

 

BriansdeMacBook-Pro:armeabi-v7a brian$ arm-linux-androideabi-readelf -d libcheckcert.so Dynamic section at offset 0x19b80 contains 27 entries:  Tag        Type                         Name/Value 0x00000003 (PLTGOT)                     0x1ad84 0x00000002 (PLTRELSZ)                   1248 (bytes) 0x00000017 (JMPREL)                     0x4200 0x00000014 (PLTREL)                     REL 0x00000011 (REL)                        0x31a8 0x00000012 (RELSZ)                      4184 (bytes) 0x00000013 (RELENT)                     8 (bytes) 0x6ffffffa (RELCOUNT)                   390 0x00000006 (SYMTAB)                     0x148 0x0000000b (SYMENT)                     16 (bytes) 0x00000005 (STRTAB)                     0x1028 0x0000000a (STRSZ)                      6825 (bytes) 0x00000004 (HASH)                       0x2ad4 0x00000001 (NEEDED)                     Shared library: [liblog.so] 0x00000001 (NEEDED)                     Shared library: [libc.so] 0x00000001 (NEEDED)                     Shared library: [libm.so] 0x00000001 (NEEDED)                     Shared library: [libstdc++.so] 0x00000001 (NEEDED)                     Shared library: [libdl.so] 0x0000000e (SONAME)                     Library soname: [libcheckcert.so] 0x0000000c (INIT)                       0x4f9c 0x0000001a (FINI_ARRAY)                 0x1a658 0x0000001c (FINI_ARRAYSZ)               8 (bytes) 0x00000019 (INIT_ARRAY)                 0x1a660 0x0000001b (INIT_ARRAYSZ)               20 (bytes) 0x0000001e (FLAGS)                      BIND_NOW 0x6ffffffb (FLAGS_1)                    Flags: NOW 0x00000000 (NULL)                       0x0

可以看到INIT和INIT_ARRAY節的地址分別為0x4f9c和0x1a660,開啟IDA pro來查看相應位置的代碼:

 

 

.text:00004F9C ; =============== S U B R O U T I N E =======================================.text:00004F9C.text:00004F9C ; Attributes: bp-based frame.text:00004F9C.text:00004F9C                 EXPORT _init.text:00004F9C _init.text:00004F9C.text:00004F9C var_8           = -8.text:00004F9C var_4           = -4.text:00004F9C.text:00004F9C                 STMFD           SP!, {R11,LR}.text:00004FA0                 MOV             R11, SP.text:00004FA4                 SUB             SP, SP, #8.text:00004FA8                 LDR             R0, =(_GLOBAL_OFFSET_TABLE_ - 0x4FB4).text:00004FAC                 ADD             R0, PC, R0 ; _GLOBAL_OFFSET_TABLE_.text:00004FB0                 MOV             R1, #4.text:00004FB4                 LDR             R2, =(aBrian_1 - 0x1AD84).text:00004FB8                 ADD             R2, R2, R0 ; "BRIAN".text:00004FBC                 LDR             R3, =(a_initEnter - 0x1AD84).text:00004FC0                 ADD             R0, R3, R0 ; "_init enter".text:00004FC4                 STR             R0, [SP,#8+var_4].text:00004FC8                 MOV             R0, R1.text:00004FCC                 MOV             R1, R2.text:00004FD0                 LDR             R2, [SP,#8+var_4].text:00004FD4                 BL              __android_log_print.text:00004FD8                 STR             R0, [SP,#8+var_8].text:00004FDC                 MOV             SP, R11.text:00004FE0                 LDMFD           SP!, {R11,PC}.text:00004FE0 ; End of function _init

 

 

 

init_array:0001A660 ; ===========================================================================.init_array:0001A660.init_array:0001A660 ; Segment type: Pure data.init_array:0001A660                 AREA .init_array, DATA.init_array:0001A660                 ; ORG 0x1A660.init_array:0001A660                 DCD _Z13myConstructorv  ; myConstructor(void).init_array:0001A664                 DCD sub_4E90.init_array:0001A668                 DCD sub_4EA8.init_array:0001A66C                 DCD sub_4F04.init_array:0001A670                 DCB    0.init_array:0001A671                 DCB    0.init_array:0001A672                 DCB    0.init_array:0001A673                 DCB    0.init_array:0001A673 ; .init_array   ends


可以看到上面的代碼中執行了我們所定義的函數,.init節就是_init函數的代碼,而.init_array節是一個指標數組,每一項對應的是一塊代碼,可以做一系列的初始化操作。那麼為什麼.init節的代碼先於.init_array節的代碼執行呢?這個要看linker的代碼了,位置在AOSP的bionic/linker目錄下,這裡只摘錄裡面的一小段代碼:

 

 

void soinfo::CallConstructors() {   ........   // DT_INIT should be called before DT_INIT_ARRAY if both are present.   CallFunction("DT_INIT", init_func);   CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);}

可以看到先執行.init節中的代碼,然後在順序執行.init_array中的各個代碼塊。

 

到這裡大家應該對_init函數、constructor屬性及.init節和.init_array節的對應情況瞭解的很清楚了吧。

下面說一個我不太清楚的地方,用readelf查看ELF中的所有符號資訊,可以看到在.rel.dyn和.rel.plt都有myConstructor符號,一個類型是R_ARM_ABS32一個是R_ARM_JUMP_SLOT。另外在IDA pro中查看myConstructor可以發現它的代碼主體是在.text節,但是也可以發現在.plt和.got節中也有myConstructor的定義。這樣的話每次顯式調用myConstructor的時候都需要通過PLT來跳轉然後從GOT表中來找到myConstructor在TEXT節中的真正地址才能執行。但在.init_array中的地址是它在TEXT節中的真正地址,初始化的時候調用myConstructor並不需要通過PLT和GOT表。不明白這是為什嗎?留待以後解決吧。

更新:上面這個問題是因為編譯器的問題,不同的編譯器編譯出來的ELF檔案是不太一樣的,上面我說的這種情況是LLVM編譯器編譯出來的,而如果用arm-linux-androideabi-*的話myConstructor符號是只有在.text節中才有,不會出現在.rel.dyn和.rel.plt中。

Android C語言_init函數和constructor屬性及.init/.init_array節探索

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.