/* Sanity check that we're really looking at a PLT relocation. */ assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); //这里是检查r_info中的重定位入口类型是否是R_386_JMP_SLOT,动态链接中函数重定位一般都为R_386_JMP_SLOT,也就是7 /* Look up the target symbol. If the normal lookup rules are not used don't look in the global scope. */ if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) { //这里判断函数是否被解析过,如果(sym->st_other)&0x03结果为0,说明没有解析过,不属于STV_PROTECTED、STV_HIDDEN或者STV_INTERNAL其中任何一种。 conststructr_found_version *version =NULL;
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) { constElfW(Half) *vernum = (constvoid *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff; version = &l->l_versions[ndx]; if (version->hash == 0) version = NULL; } //这部分获取version信息,我们可以发现version是使用我们的r_info进行赋值,如果我们r_info的重定位入口符号下标异常从而导致ndx数值异常,很可能导致l_versions[ndx]数组越界到不可读位置导致程序崩溃。
/* We need to keep the scope around so do some locking. This is not necessary for objects which cannot be unloaded or when we are not using any threads (yet). */ int flags = DL_LOOKUP_ADD_DEPENDENCY; if (!RTLD_SINGLE_THREAD_P) { THREAD_GSCOPE_SET_FLAG (); flags |= DL_LOOKUP_GSCOPE_LOCK; }
/* Currently result contains the base load address (or link map) of the object that defines sym. Now add in the symbol offset. */ value = DL_FIXUP_MAKE_VALUE (result, sym ? (LOOKUP_VALUE_ADDRESS (result) + sym->st_value) : 0); } else { /* We already found the symbol. The module (and therefore its load address) is also known. */ value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value); result = l; } /* And now perhaps the relocation addend. */ value = elf_machine_plt_value (l, reloc, value); if (sym != NULL && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value)); //这一部分先通过strtab(字符串表的基地址)加上st_name(字符串对应字符串表的下标)得到函数的字符串,从已经装载的共享库找到最终符号的地址,得到符号对其重定位,加上libc的装载地址得到最终地址,保存在value中 /* Finally, fix up the plt itself. */ if (__glibc_unlikely (GLRO(dl_bind_not))) return value; return elf_machine_fixup_plt (l, result, reloc, rel_addr, value); //这部分是使用elf_machine_fixup_plt对函数地址进行修正,将函数真实地址写入got表 }
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) { ...... } else { /* We already found the symbol. The module (and therefore its load address) is also known. */ value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value); result = l; }
/* Structure describing a loaded shared object. The `l_next' and `l_prev' members form a chain of all the shared objects loaded at startup. These data structures exist in space used by the run-time dynamic linker; modifying them may have disastrous results. This data structure might change in future, if necessary. User-level programs must avoid defining objects of this type. */
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. */
/* All following members are internal to the dynamic linker. They may change without notice. */
/* This is an element which is only ever different from a pointer to the very same copy of this type for ld.so when it is used in more than one namespace. */ structlink_map *l_real;
/* Number of the namespace this link map belongs to. */ Lmid_t l_ns;
structlibname_list *l_libname; /* Indexed pointers to dynamic section. [0,DT_NUM) are indexed by the processor-independent tags. [DT_NUM,DT_NUM+DT_THISPROCNUM) are indexed by the tag minus DT_LOPROC. [DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM) are indexed by DT_VERSIONTAGIDX(tagvalue). [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM, DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM) are indexed by DT_EXTRATAGIDX(tagvalue). [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM, DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM) are indexed by DT_VALTAGIDX(tagvalue) and [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM, DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM+DT_ADDRNUM) are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>. */
ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM]; constElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */ ElfW(Addr) l_entry; /* Entry point location. */ ElfW(Half) l_phnum; /* Number of program header entries. */ ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */
/* Array of DT_NEEDED dependencies and their dependencies, in dependency order for symbol lookup (with and without duplicates). There is no entry before the dependencies have been loaded. */ structr_scope_eleml_searchlist;
/* We need a special searchlist to process objects marked with DT_SYMBOLIC. */ structr_scope_eleml_symbolic_searchlist;
/* Dependent object that first caused this object to be loaded. */ structlink_map *l_loader;
/* Array with version names. */ structr_found_version *l_versions; unsignedint l_nversions;
unsignedint l_direct_opencount; /* Reference count for dlopen/dlclose. */ enum /* Wherethisobjectcamefrom. */ { lt_executable, /* The main executable program. */ lt_library, /* Library needed by main executable. */ lt_loaded /* Extra run-time loaded shared object. */ } l_type:2; unsignedint l_relocated:1; /* Nonzero if object's relocations done. */ unsignedint l_init_called:1; /* Nonzero if DT_INIT function called. */ unsignedint l_global:1; /* Nonzero if object in _dl_global_scope. */ unsignedint l_reserved:2; /* Reserved for internal use. */ unsignedint l_phdr_allocated:1; /* Nonzero if the data structure pointed to by `l_phdr' is allocated. */ unsignedint l_soname_added:1; /* Nonzero if the SONAME is for sure in the l_libname list. */ unsignedint l_faked:1; /* Nonzero if this is a faked descriptor without associated file. */ unsignedint l_need_tls_init:1; /* Nonzero if GL(dl_init_static_tls) should be called on this link map when relocation finishes. */ unsignedint l_auditing:1; /* Nonzero if the DSO is used in auditing. */ unsignedint l_audit_any_plt:1; /* Nonzero if at least one audit module is interested in the PLT interception.*/ unsignedint l_removed:1; /* Nozero if the object cannot be used anymore since it is removed. */ unsignedint l_contiguous:1; /* Nonzero if inter-segment holes are mprotected or if no holes are present at all. */ unsignedint l_symbolic_in_local_scope:1; /* Nonzero if l_local_scope during LD_TRACE_PRELINKING=1 contains any DT_SYMBOLIC libraries. */ unsignedint l_free_initfini:1; /* Nonzero if l_initfini can be freed, ie. not allocated with the dummy malloc in ld.so. */
/* Collected information about own RPATH directories. */ structr_search_path_structl_rpath_dirs;
/* Pointer to the version information if available. */ ElfW(Versym) *l_versyms;
/* String specifying the path where this object was found. */ constchar *l_origin;
/* Start and finish of memory map for this object. l_map_start need not be the same as l_addr. */ ElfW(Addr) l_map_start, l_map_end; /* End of the executable part of the mapping. */ ElfW(Addr) l_text_end;
/* Default array for 'l_scope'. */ structr_scope_elem *l_scope_mem[4]; /* Size of array allocated for 'l_scope'. */ size_t l_scope_max; /* This is an array defining the lookup scope for this link map. There are initially at most three different scope lists. */ structr_scope_elem **l_scope;
/* A similar array, this time only with the local scope. This is used occasionally. */ structr_scope_elem *l_local_scope[2];
/* This information is kept to check for sure whether a shared object is the same as one already loaded. */ structr_file_idl_file_id;
/* Collected information about own RUNPATH directories. */ structr_search_path_structl_runpath_dirs;
/* List of object in order of the init and fini calls. */ structlink_map **l_initfini;
/* List of the dependencies introduced through symbol binding. */ structlink_map_reldeps { unsignedint act; structlink_map *list[]; } *l_reldeps; unsignedint l_reldepsmax;
/* Nonzero if the DSO is used. */ unsignedint l_used;
/* Various flag words. */ ElfW(Word) l_feature_1; ElfW(Word) l_flags_1; ElfW(Word) l_flags;
/* Start of the initialization image. */ void *l_tls_initimage; /* Size of the initialization image. */ size_t l_tls_initimage_size; /* Size of the TLS block. */ size_t l_tls_blocksize; /* Alignment requirement of the TLS block. */ size_t l_tls_align; /* Offset of first byte module alignment. */ size_t l_tls_firstbyte_offset; #ifndef NO_TLS_OFFSET # define NO_TLS_OFFSET 0 #endif #ifndef FORCED_DYNAMIC_TLS_OFFSET # if NO_TLS_OFFSET == 0 # define FORCED_DYNAMIC_TLS_OFFSET -1 # elif NO_TLS_OFFSET == -1 # define FORCED_DYNAMIC_TLS_OFFSET -2 # else # error"FORCED_DYNAMIC_TLS_OFFSET is not defined" # endif #endif /* For objects present at startup time: offset in the static TLS block. */ ptrdiff_t l_tls_offset; /* Index of the module in the dtv array. */ size_t l_tls_modid;
/* Number of thread_local objects constructed by this DSO. This is atomically accessed and modified and is not always protected by the load lock. See also: CONCURRENCY NOTES in cxa_thread_atexit_impl.c. */ size_t l_tls_dtor_count;
/* Information used to change permission after the relocations are done. */ ElfW(Addr) l_relro_addr; size_t l_relro_size;
unsignedlonglongint l_serial;
/* Audit information. This array apparent must be the last in the structure. Never add something after it. */ structauditstate { uintptr_t cookie; unsignedint bindflags; } l_audit[0]; };