The technology of ELF dynamic library loading

Source: Internet
Author: User

Libraries are used to package similar functions in a single unit. Linux supports two types of libraries: static libraries (statically bound to programs at compile time) and dynamic libraries (bound to programs at run time). The dynamic libraries used by Linux systems are in ELF format, with the suffix named so. 1 Load

The dynamic library is divided into segments, and segments are divided into different types:

Pt_load segment: Contains code or data that needs to be mapped into memory, each segment has different access rights (read, some, execute);

Pt_dynamic: Contains dynamic link information, such as symbol table, relocation table, referenced other library, and so on.

Other segment types are temporarily not indicated.

The loader maps the contents of the first pt_load segment of the library file to the last Pt_load segment to a contiguous memory address space (the benefit is that arbitrary code and the relative address of the data are fixed), and its first address is called the base site (pictured).

The loading of the library only maps the contents of the file to the memory address, but does not actually read the file data, and the corresponding file data is read into memory by the operating system when the memory page fault is abnormal. Deferred read files can speed up the loading of a library. 1.1 Pre-link

In general, the base address of the map is not fixed, but if the dynamic Library uses theprelink technique, it is mapped to the intended address (saved on the file). If the intended address range is already occupied, the load fails (Androidlinker is so that other loaders may be different). The advantage of PreLink is that it simplifies relocation and speeds up loading. 2 Relocation 2.1 Internal functions and variables

In the absence of the use of PreLink, the base address of the library is not fixed (the runtime is determined) and its global variables and the absolute addresses of the functions are not fixed. Because the relative addresses of arbitrary code and data are fixed after Kuga (as described in the previous section), some systems (such as x86) can use relative addresses to access global variables and functions. The arm system cannot use a large range of offsets directly in the instruction (but can be specified by registers) because of the instruction length limitation (32 bits), and the absolute address is superior to the relative address in execution efficiency, so it still needs relocation.

As in this example:

__ATTRIBUTE__ ((Visibility ("hidden")) int errbase = 1;
void Seterr () {errbase = 0x999;}

Compile so, then decompile (ARM architecture):

$ gcc-shared-nostdlib-o libtest.so test.c
$ objdump-dlibtest.so
000002c4<seterr>:
2c4:  mov    ip,sp
2c8:  push   {fp,ip, LR, PC}
2cc:  Sub    fp,ip, #4
2d0:    Ldr r2,[pc, #12]      ; r2 = &errbase
2d4:  mov    R3, #2448          ; r3 = 990 2d8
:  add    r3,r3, #9         R3 + + 9
2dc:  str    R3,[R2]           ; *r2 = R3
2e0:  ldm    sp,{fp, SP, PC}
2e4:  . Word  0x0000109c        ; This holds the address of the errbase variable.

To view the relocation table:

$ readelf-rlibtest.so
relocationsection '. Rel.dyn ' at offset 0X2BC contains 1 entries:
offset    Info       Type            sym.value  Sym. Name
000002e4  00000017   r_arm_relative

Comparing the assembly code with the relocation table, 2e4 is the offset that holds the address of the errbase variable.

Reposition a table entry in the table with a relative type, pointing to the relative address of the variable and function, and the loader adds it to the base address, making it an absolute address. If you use PreLink, you do not need to relocate. 2.2 External functions and variables

External variables and functions refer to the variables and functions of the target library referencing dependent libraries, requiring the loader to find the corresponding name and absolute address in the symbol table of the dependent library, and then write to the Global offset tableof the target library (globaloffset table , referred to as GOT). The target library accesses external variables and functions through got.

External variable reposition table entry corresponding to a glob_dat type , external function relocation corresponds to a jmp_slot type table entry, the value of the table entry is an absolute address of an external variable or function , which is set by the loader.

As in this example:

extern interrbase;
void Seterr () {errbase = 0x999;}

Compile so, then decompile (ARM architecture):

$ gcc-shared-nostdlib-o libtest.so test.c
$ objdump-dlibtest.so
00000218<seterr>:
218:  push   {fp}
21c:  add    fp,sp, #0
:  ldr    r3,[pc, #28]    ; r3=got offset
224:  Add    r3,pc, R3       ; R3=got address
228:  ldr    r2,[pc, #24]    r2=errbase entry at got offset
22c:  ldr    R3,[R3, R2]     ; R3=errbase address
230:  ldr    r2,[pc, #20]; r2=0x999 234
:  str    R2,[R3]         ; r3=r2
238:  add    sp,fp, #0
23c:  pop    {fp}
:  bx     LR
244:  . Word  0X00008DC4      ; Got offset
248:  . Word  0x0000000c      errbase at got offset
24c:  . Word  0x00000999

To view the relocation table:

$readelf-rlibtest.so
relocationsection '. Rel.dyn ' at offset 0x210 contains 1 entries:
offset      Info        Type              Sym.value    sym.name
00008ffc    00000415    r_arm_glob_dat    00000000     errbase

8FFCC exactly corresponds to the Errbase got table entry address. 2.3 Deferred binding

The relocation of external functions and variables needs to find the symbol table of the dependent library, and it is less efficient to do string comparisons, although generally one library uses fewer external variables and functions. If more external functions are used, the Process link table (procedurelinkagetable, or PLT)can be used to speed up dynamic library loading. Delays the positioning of external functions to the first call (called deferred binding). Function delay binding requires the compiler to generate additional code for the function call, which is implemented primarily by the compiler.

Look at this example:

VOIDPRINTF1 (const char*, ...);
void Seterr () {PRINTF1 ("seterr\n");}

Corresponding assembly code (X86-64):

4c0<printf1@plt>:
4c0:  jmpq   *0x200b3a (%rip)
4c6: Pushq $0x0
4CB:  JMPQ   4b0 <_init+0x18>

5ac <seterr>:
5ac:  push   %rbp
5ad:  mov    %RSP,%RBP
5b0:  Lea    0x5f (%rip),%rdi
5b7:  mov    $0x0,%eax
5BC:  callq  4C0
5c1:  pop    %rbp
5c2:  retq

Calling PRINTF1 calls Printf1@plt, and then jumps to *0x200b3a (%rip), which is * (base address +0x201000).

If this is the first execution, the value of the *0x (base address +0x201000) is (base address +4c6), and the following code performs the function binding, and the corresponding relocation entry is:

$ readelf-rlibtest.so
relocationsection '. Rela.plt ' at offset 0x468 contains 2 entries:
201000 000300000007 r_x8 6_64_jump_slo  PRINTF1 + 0

After binding *0x (base address +0x201000) corresponds to the PRINTF1 function's address, the next time you enter the PRINTF1@PLT, you can jump directly to the PRINTF1 function. 2.4-bit independent code

In general, code and read-only data for programs and dynamic libraries can be shared by multiple processes after they are loaded into memory, but dirty data that is written cannot be shared by multiple processes. Relative type relocation modifies the variable address of the code snippet, causing the code snippet to be contaminated so that it cannot be shared by multiple processes. In order for the code snippets of a dynamic library to be shared between processes, you can have the compiler compile the location-independent code ( PIC)by got to access the variables and functions.

PIC Allows code snippets to be shared between processes, saving memory, but accessing variables and functions by got tables is a bit slower than relative positioning, and you can not use pic If you don't need to.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.