typedefstruct { Elf64_Sxword d_tag; /* Dynamic entry type */ union { Elf64_Xword d_val; /* Integer value */ Elf64_Addr d_ptr; /* Address value */ } d_un; } Elf64_Dyn;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
structlink_map { /* These first few members are part of the protocol with the debugger. This is the same format used in SVR4. */
ElfW(Addr) l_addr; /* Difference between the address in the ELF file and the addresses in memory. */ char *l_name; /* Absolute file name object was found in. */ ElfW(Dyn) *l_ld; /* Dynamic section of the shared object. */ structlink_map *l_next, *l_prev; /* Chain of loaded objects. */ // ... /* Indexed pointers to dynamic section. */ ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM]; // ... };
1 2 3 4 5 6 7 8 9 10 11 12
// D_PTR 的两个定义用于:完成重定位之后和完成重定位之前,区别在于有没有加上 difference 。 /* All references to the value of l_info[DT_PLTGOT], l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA], l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)] have to be accessed via the D_PTR macro. The macro is needed since for most architectures the entry is already relocated - but for some not and we need to relocate at access time. */ #ifdef DL_RO_DYN_SECTION # define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr) #else # define D_PTR(map, i) (map)->i->d_un.d_ptr #endif
1 2 3 4 5 6 7
# readelf --dynamic main | head -n 8 | tail -n 6 Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libfoo.so] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000001d (RUNPATH) Library runpath: [/root/test] 0x000000000000000c (INIT) 0x1000 0x000000000000000d (FINI) 0x11b4
/* Relocation table entry with addend (in section of type SHT_RELA). */ typedefstruct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */ } Elf64_Rela;
1 2 3
# readelf --dynamic main | grep -E "Tag|JMPREL" Tag Type Name/Value 0x0000000000000017 (JMPREL) 0x578
1 2 3 4 5
# readelf --section-headers main | grep -E "Nr|578" -A1 | grep -v "\-\-" [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [10] .rela.plt RELA 0000000000000578 00000578 0000000000000018 0000000000000018 AI 5 23 8
/* We use this macro to refer to ELF macros independent of the native wordsize. `ELFW(R_TYPE)' is used in place of `ELF32_R_TYPE' or `ELF64_R_TYPE'. */ #define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) #define ELF64_R_SYM(i) ((i) >> 32)
# readelf --dynamic main | grep -E "Tag|STRTAB" Tag Type Name/Value 0x0000000000000005 (STRTAB) 0x3f0
1 2 3 4 5
# readelf --section-headers main | grep -E "Nr|3f0" -A1 | grep -v "\-\-" [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 6] .dynstr STRTAB 00000000000003f0 000003f0 000000000000009a 0000000000000000 A 0 0 1
1 2 3 4 5
# export string_table_start_addr=0x3f0 # export st_name=0x50 # od --skip-bytes=$(($string_table_start_addr + $st_name)) --read-bytes=0x8 --format=xC -c main 0002100 5f 5a 33 66 6f 6f 76 00 _ Z 3 f o o v \0
The scope describes which libraries should be searched for symbol lookups occuring within the scope owner. (By the way, given that lookup scope may differ by caller, implementing dlsym() is not that trivial.) It is further divided into scope elements (struct r_scope_elem) – a single scope element basically describes a single search list of libraries, and the scope (link_map.l_scope is the scope used for symbol lookup) is list of such scope elements.
To reiterate, a symbol lookup scope is a list of lists! Then, when looking up a symbol, the linker walks the lists in the order they are listed in the scope. But what really are the scope elements? There are two usual kinds:
The "global scope" – all libraries (ahem, link_maps) that have been requested to be loaded by the main program (what ldd on the binary file of the main program would print out, plus dlopen()ed stuff).
The "local scope" – DT_NEEDED library dependencies of the current link_map (what ldd on the binary file of the library would print out, plus dlopen()ed stuff).
The global scope is shared between all link_maps (in the current namespace), while the local scope is owned by a particular library.
/* Relocation table entry with addend (in section of type SHT_RELA). */ typedefstruct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */ } Elf64_Rela;
1 2 3
# readelf --dynamic main | grep -E "Tag|JMPREL" Tag Type Name/Value 0x0000000000000017 (JMPREL) 0x578
1 2 3 4 5
# readelf --section-headers main | grep -E "Nr|578" -A1 | grep -v "\-\-" [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [10] .rela.plt RELA 0000000000000578 00000578 0000000000000018 0000000000000018 AI 5 23 8