There is no distinction of different modules within a shared library. A shared library is a single executable file. The shared library scheme we use today is SunOS'. Why is lazy binding slow? I can think of two factors.įirst, binding granularity. got.plt entry has been updated to the actual function address, subsequent calls to foo will bypass the PLT resolver. got.plt entry, and then performs a tail call to the resolved address. got.plt descriptor, writes the resolved address to the. The PLT resolver in ld.so looks up the symbol with the. Jmpq *.got.plt+16(%rip) # Jump to the PLT resolver in *.got.plt+24(%rip) # The first call got.plt+16 (PLT resolver in ld.so) with an extra argument (descriptor for the current component). The PLT header is a stub calling the function address stored at. got.plt entry) and jumps to the PLT header. The pushq instructions pushes a descriptor (for the. got.plt entry refers to the pushq instruction immediately after the jmpq. In the lazy binding scheme, ld.so does minimum work to ensure the jmp instruction lands in a trampoline which will tail call the PLT resolver in ld.so. Table indirection archive#This is because shared objects usually need to export all symbols which can defeat the archive member extraction trick and linker garbage collection.Īnyhow, eagerly resolving all R_*_JUMP_SLOT relocations had a significant overhead. Table indirection code#In addition, a shared object has more code than the portion linked into the executable with static linking. There is some slowdown due to work before the program starts. The ELF dynamic shared library scheme postpones binding from the link time to the load time. The extra instructions and extra entries in. See Dependency related linker options for details. 1Įager binding has a bonus: it can detect underlinking problems. If the component is linked with ld -z now, the linker will set the DF_1_NOW dynamic tag, and ld.so will use eager binding.Įager binding can also be enabled with the environment variable LD_BIND_NOW=1.įor better understanding, we can ignore many instructions in the assembly output above. Table indirection full#However, with the rise of security hardening on Linux distributions, many have switched to full RELRO linking scheme. In other ld.so implementations, lazy binding is usually the default. Table indirection android#This is the model used by musl and Android bionic. got.plt entry is guaranteed to hold the address of the target function. Before ld.so transfers control to the component, during relocation resolving, ld.so resolves the address of foo and writes it into the. Note: some architectures use R_*_JMP_SLOT instead of R_*_JUMP_SLOT for the dynamic relocation type. Resolving a function address is also called a binding. Each entry is relocated by an R_*_JUMP_SLOT dynamic relocation describing the target function symbol. The subsequent entries are for resolved function addresses. got.plt is the address of the PLT resolver. got.plt are reserved by ld.so.got.plt is a descriptor of the current component while. got.plt is the link time address of _ and. got.plt holds an array of word size entries. The remaining two instructions will be described when introducing lazy binding. The first jmpq instruction loads an entry from. It is just that objdump displays the PLT entry as We use the notation to describe a stub. In the relocatable object file, we have two call instructions. # relocated by R_X86_64_JUMP_SLOT referencing bar # relocated by R_X86_64_JUMP_SLOT referencing foo quad Obj_Entry used to indicate the current component # set by ld.so quad link-time address of _DYNAMIC # set by linker Procedure Linkage TableĮLF uses Procedure Linkage Table to provide the indirection. Therefore, the prevailing scheme is to add a level of indirection analogous to that provided by the Global Offset Table for data. # On ELF x86-64, the R_X86_64_PC32 relocation type is used. # The instructions are patched at runtime. In addition, the number of relocations would be dependent on the number of calls, which can be large. In All about Global Offset Table, I mentioned that linker/loader developers often frowned upon text relocations because the text segment will be unshareable. In an executable or shared object (called a component in ELF), if the target is bound to the same component, the instruction has a fixed encoding at link time otherwise the target is unknown at link time and there are two choices: the distance to the target is encoded in the instruction. Many architectures encode a branch/jump/call instruction with PC-relative addressing, i.e.
0 Comments
Leave a Reply. |
Details
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |