struct link_map {
Elf64_Addr l_addr;
char *l_name;
Elf64_Dyn *l_ld;//Dynamic的地址
struct link_map *l_next;
struct link_map *l_prev;
struct link_map *l_real;
Lmid_t l_ns;
struct libname_list *l_libname;
Elf64_Dyn *l_info[76];//l_info 里面包含的就是动态链接的各个表的信息,实际就是.dynmic节
const Elf64_Phdr *l_phdr;
Elf64_Addr l_entry;
Elf64_Half l_phnum;
Elf64_Half l_ldnum;
struct r_scope_elem l_searchlist;
struct r_scope_elem l_symbolic_searchlist;
struct link_map *l_loader;
struct r_found_version *l_versions;
unsigned int l_nversions;
Elf_Symndx l_nbuckets;
Elf32_Word l_gnu_bitmask_idxbits;
Elf32_Word l_gnu_shift;
const Elf64_Addr *l_gnu_bitmask;
union {
const Elf32_Word *l_gnu_buckets;
const Elf_Symndx *l_chain;
};
union {
const Elf32_Word *l_gnu_chain_zero;
const Elf_Symndx *l_buckets;
};
unsigned int l_direct_opencount;
enum {lt_executable, lt_library, lt_loaded} l_type : 2;
unsigned int l_relocated : 1;
unsigned int l_init_called : 1;
unsigned int l_global : 1;
unsigned int l_reserved : 2;
unsigned int l_phdr_allocated : 1;
unsigned int l_soname_added : 1;
unsigned int l_faked : 1;
unsigned int l_need_tls_init : 1;
unsigned int l_auditing : 1;
unsigned int l_audit_any_plt : 1;
unsigned int l_removed : 1;
unsigned int l_contiguous : 1;
unsigned int l_symbolic_in_local_scope : 1;
unsigned int l_free_initfini : 1;
struct r_search_path_struct l_rpath_dirs;
struct reloc_result *l_reloc_result;
Elf64_Versym *l_versyms;
const char *l_origin;
Elf64_Addr l_map_start;
Elf64_Addr l_map_end;
Elf64_Addr l_text_end;
struct r_scope_elem *l_scope_mem[4];
size_t l_scope_max;
struct r_scope_elem **l_scope;
struct r_scope_elem *l_local_scope[2];
struct r_file_id l_file_id;
struct r_search_path_struct l_runpath_dirs;
struct link_map **l_initfini;
struct link_map_reldeps *l_reldeps;
unsigned int l_reldepsmax;
unsigned int l_used;
Elf64_Word l_feature_1;
Elf64_Word l_flags_1;
Elf64_Word l_flags;
int l_idx;
struct link_map_machine l_mach;
struct {
const Elf64_Sym *sym;
int type_class;
struct link_map *value;
const Elf64_Sym *ret;
} l_lookup_cache;
void *l_tls_initimage;
size_t l_tls_initimage_size;
size_t l_tls_blocksize;
size_t l_tls_align;
size_t l_tls_firstbyte_offset;
ptrdiff_t l_tls_offset;
size_t l_tls_modid;
size_t l_tls_dtor_count;
Elf64_Addr l_relro_addr;
size_t l_relro_size;
unsigned long long l_serial;
struct auditstate l_audit[];
}
typedef struct
{
Elf64_Word st_name; /* 在.Dynstr中的偏移,指向一个str,占4字节*/
unsigned char st_info; /* Symbol type and binding 占1字节*/
unsigned char st_other; /* Symbol visibility 占1字节*/
Elf64_Section st_shndx; /* Section index 占2字节*/
Elf64_Addr st_value; /* Symbol value 占8字节*/
Elf64_Xword st_size; /* Symbol size 占8字节*/
} Elf64_Sym;
typedef struct
{
Elf64_Sxword d_tag; /* Dynamic entry type */
union
{
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
} Elf64_Dyn;
typedef struct
{
Elf64_Addr r_offset; /*r_offset+l_addr为一个指向got表的指针,记录着该函数在got表中的位置,正常情况下l_addr=0*/
Elf64_Xword r_info; /*r_info>>32就是在dynsym中的下标,最低位要为7*/
Elf64_Sxword r_append /*Addend */
} Elf64_Rela;
Dynmic节由Elf64_Dyn结构体构成
Dynsym节由Elf64_Sym结构体构成
.rel.plt节由Elf64_Rela结构体构成
_dl_runtime_resolve(link_map,reloc_arg)实际上就是执行了_dl_fixup



进行动态链接的流程:
1.根据想要连接的函数确定偏移reloc_arg(体现在plt[1]表里面的push)
2.找到.rel.plt里对应的ELF64_Rela表项
3.根据ELF64_Rela里的r_info确定该函数对应.dynsym里的哪一个Elf64_sym项(在64位中r_info>>32即为表项下标)
4.在32位程序中会根据Elf32_sym里的st_name在跳转到.dynstr里寻找字符串,再根据这个字符串到libc中去进行匹配查询,最后把libc基址+st_value作为该函数的真实地址写入r_offset这一指针指向的位置,正常情况下该指针指向got表对应的表项
5.而在64位程序中,由于要绕开保护(令st_other!=0),所以不会经过查找字符串这一步骤,最终地址的计算方式变成了l_addr+st_value。在Elf64_sym结构体中,st_value与表头的间隔为8字节,所以如果能让sym指向a函数的got-8位置(假设a是任意一个已解析的函数),那么st_value恰好就是a的got位置,其值就是a函数的真实地址,那么只要让l_addr为system函数与a函数在libc里面的偏移offset,最终解析出来的地址就是真正的system地址了