This article focuses on "Android C language _init functions and constructor properties and. Init/.init_array section exploration", mainly related to the Android C language _init functions and constructor properties and. init/. Init_array section explores the content, for Android C language _init functions and constructor properties and. Init/.init_array Festival Explore interested students can refer to.
Learn about the C language apes know that there are two ways to get some code to execute before any other function when so or the executable is loaded, one to define a void _init (void) function, and one to declare the constructor property after the function. So what's the difference between the two ways of doing it? In what order? What is the difference between a person who understands the elf file format and asks where they are in the file? This article is to answer these questions.
First you need to understand the elf file format, here is not verbose, do not know people can search for a look.
Here's an example of adding the following lines to your Android project's C + + code:
... #ifdef __cplusplusextern "C" {#endifvoid _init (void) {Mlog_info ("_init enter");} #ifdef __cplusplus} #endifvoid __attribute__ ((constructor)) Myconstructor (void) {Mlog_info ("Myconstructor enter\n");} ........
My side compiled is libcheckcert.so file, put on the phone to run the result is:
........ 12-13 11:04:46.603:i/brian (12203): _init enter12-13 11:04:46.603:i/brian (12203): Myconstructor enter .....
The _init function is the first to run, why is it so? People who understand Elf files know that there are. Init and. Init_array, which are the two sections of the ELF files that are used to initialize when they are loaded, and what do they have to do with the _init function and the constructor attribute? Below we need to see with Readelf and Ida Pro, first readelf-d libcheckcert.so to see the dynamic segment of Elf:
briansdemacbook-pro:armeabi-v7a brian$ arm-linux-androideabi-readelf-d libcheckcert.so Dynamic section at offset 0X19B80 contains Entries:tag Type name/value 0x00000003 (pltgot) 0 x1ad84 0x00000002 (pltrelsz) 1248 (bytes) 0x00000017 (jmprel) 0x4200 0x00000014 (PLT REL) rel 0x00000011 (rel) 0x31a8 0x00000012 (RELSZ) 4184 ( bytes) 0x00000013 (relent) 8 (bytes) 0x6ffffffa (relcount) 390 0x00000006 (Symtab) 0x148 0x0000000b (syment) (bytes) 0x00000005 (strtab) 0x1028 0x0000000a (strsz) 6825 (bytes) 0x00000004 (HASH) 0x2ad4 0x00000001 (NEEDED) Shared library: [liblog.so] 0x00000001 (NEEDED) shared library: [libc.so] 0x0000000 1 (NEEDED) Shared library: [libm.so] 0x00000001 (NEEDED) Shared library: [libstdc++.so] 0x00000001 (NEEDED) Shared library: [libdl.so] 0x0000000e (SONAME) library SONAME: [libcheckcert.so] 0x00000 00c (INIT) 0x4f9c 0x0000001a (Fini_array) 0x1a658 0x0000001c (Fini_arraysz) 8 (bytes) 0x00000019 (init_array) 0x1a660 0x0000001b (Init_arraysz) (bytes) 0x00000 01e (FLAGS) Bind_now 0x6ffffffb (flags_1) Flags:now 0x00000000 (NULL) 0x0
You can see the addresses for the Init and Init_array sections, respectively, 0x4f9c and 0x1a660, and open Ida Pro to see the code at the appropriate location:
. 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 A DD R0, PC, R0; _global_offset_table_.text:00004fb0 MOV R1, #4. TEXT:00004FB4 LDR R 2, = (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:0000 4fd4 BL __android_log_print.text:00004fd8 STR R0, [SP, #8 +var_8].t EXT:00004FDC MOV SP, r11.text:00004fe0 ldmfd sp!, {r11,pc}.text:0000 4FE0; End of function _init
init_array:0001a660; ===========================================================================.init_array:0001a660.init_array:0 001a660; 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
You can see that the above code executes the function we have defined, and. The. Init section is the code for the _init function, and the. Init_array section is an array of pointers, each of which corresponds to a block of code that can be initialized in a series of steps. So why is the code of the. Init section executed before the code of the. Init_array section? This depends on the linker code, located in the Aosp Bionic/linker directory, here is only a short excerpt inside the code:
void Soinfo::callconstructors () { ... Dt_init should be called before Dt_init_array if both is present. CallFunction ("Dt_init", Init_func); Callarray ("Dt_init_array", Init_array, Init_array_count, false);}
You can see that the code in the. Init section is executed first, and then the individual code blocks in the. Init_array are executed sequentially.
Here you should understand the _init function, the constructor attribute, and the. Init section and the. Init_array section.
Here's a place I'm not sure about, using readelf to view all the symbol information in the ELF, you can see that both the. Rel.dyn and. REL.PLT have myconstructor symbols, one type is R_ARM_ABS32 and the other is R_arm_jump_slot. In addition, viewing Myconstructor in Ida Pro can find that its code body is in the. Text section, but you can also find definitions of myconstructor in the. plt and. Got sections. In this case, each time you explicitly call myconstructor, you need to jump through the PLT and find the true address of myconstructor in the text section from the Got table to execute. But the address in. Init_array is its true address in the text section, and when initialized, calling Myconstructor does not need to pass the PLT and got tables. Do not understand why this is? Let's settle it later.
Update: The above problem is because of the compiler problem, different compiler compiled Elf file is not quite the same, the above I said this situation is LLVM compiler compiled, and if used arm-linux-androideabi-* The Myconstructor symbol is only available in the. Text section and does not appear in the. Rel.dyn and. Rel.plt.
Android C language _init functions and constructor properties and. Init/.init_array section Exploration