//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker.cpp
staticsoinfo*find_library(constchar*name)->staticsoinfo*find_library_internal(constchar*name){if(name==NULL){returnsomain;}soinfo*si=find_loaded_library(name);if(si!=NULL){if(si->flags&FLAG_LINKED){returnsi;}DL_ERR("OOPS: recursive link to \"%s\"",si->name);returnNULL;}TRACE("[ '%s' has not been loaded yet. Locating...]",name);si=load_library(name);if(si==NULL){returnNULL;}// At this point we know that whatever is loaded @ base is a valid ELF
// shared library whose segments are properly mapped in.
TRACE("[ init_library base=0x%08x sz=0x%08x name='%s' ]",si->base,si->size,si->name);if(!soinfo_link_image(si)){munmap(reinterpret_cast<void*>(si->base),si->size);soinfo_free(si);returnNULL;}returnsi;}
//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker.cpp
staticsoinfo*load_library(constchar*name){// Open the file.
intfd=open_library(name);if(fd==-1){DL_ERR("library \"%s\" not found",name);returnNULL;}// Read the ELF header and load the segments.
ElfReaderelf_reader(name,fd);if(!elf_reader.Load()){returnNULL;}constchar*bname=strrchr(name,'/');soinfo*si=soinfo_alloc(bname?bname+1:name);if(si==NULL){returnNULL;}si->base=elf_reader.load_start();si->size=elf_reader.load_size();si->load_bias=elf_reader.load_bias();si->flags=0;si->entry=0;si->dynamic=NULL;si->phnum=elf_reader.phdr_count();si->phdr=elf_reader.loaded_phdr();returnsi;}
//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker_phdr.cpp
Elf32_Ehdrheader_;boolElfReader::ReadElfHeader(){ssize_trc=TEMP_FAILURE_RETRY(read(fd_,&header_,sizeof(header_)));if(rc<0){DL_ERR("can't read file \"%s\": %s",name_,strerror(errno));returnfalse;}if(rc!=sizeof(header_)){DL_ERR("\"%s\" is too small to be an ELF executable",name_);returnfalse;}returntrue;}
//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker_phdr.cpp
boolElfReader::ReadProgramHeader(){phdr_num_=header_.e_phnum;// Like the kernel, we only accept program header tables that
// are smaller than 64KiB.
if(phdr_num_<1||phdr_num_>65536/sizeof(Elf32_Phdr)){DL_ERR("\"%s\" has invalid e_phnum: %d",name_,phdr_num_);returnfalse;}Elf32_Addrpage_min=PAGE_START(header_.e_phoff);Elf32_Addrpage_max=PAGE_END(header_.e_phoff+(phdr_num_*sizeof(Elf32_Phdr)));Elf32_Addrpage_offset=PAGE_OFFSET(header_.e_phoff);phdr_size_=page_max-page_min;void*mmap_result=mmap(NULL,phdr_size_,PROT_READ,MAP_PRIVATE,fd_,page_min);if(mmap_result==MAP_FAILED){DL_ERR("\"%s\" phdr mmap failed: %s",name_,strerror(errno));returnfalse;}phdr_mmap_=mmap_result;phdr_table_=reinterpret_cast<Elf32_Phdr*>(reinterpret_cast<char*>(mmap_result)+page_offset);returntrue;}
//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker_phdr.cpp
boolElfReader::ReserveAddressSpace(){Elf32_Addrmin_vaddr;load_size_=phdr_table_get_load_size(phdr_table_,phdr_num_,&min_vaddr);if(load_size_==0){DL_ERR("\"%s\" has no loadable segments",name_);returnfalse;}uint8_t*addr=reinterpret_cast<uint8_t*>(min_vaddr);intmmap_flags=MAP_PRIVATE|MAP_ANONYMOUS;void*start=mmap(addr,load_size_,PROT_NONE,mmap_flags,-1,0);if(start==MAP_FAILED){DL_ERR("couldn't reserve %d bytes of address space for \"%s\"",load_size_,name_);returnfalse;}load_start_=start;load_bias_=reinterpret_cast<uint8_t*>(start)-addr;returntrue;}
//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker_phdr.cpp
boolElfReader::LoadSegments(){for(size_ti=0;i<phdr_num_;++i){constElf32_Phdr*phdr=&phdr_table_[i];if(phdr->p_type!=PT_LOAD){continue;}// Segment addresses in memory.
Elf32_Addrseg_start=phdr->p_vaddr+load_bias_;Elf32_Addrseg_end=seg_start+phdr->p_memsz;Elf32_Addrseg_page_start=PAGE_START(seg_start);Elf32_Addrseg_page_end=PAGE_END(seg_end);Elf32_Addrseg_file_end=seg_start+phdr->p_filesz;// File offsets.
Elf32_Addrfile_start=phdr->p_offset;Elf32_Addrfile_end=file_start+phdr->p_filesz;Elf32_Addrfile_page_start=PAGE_START(file_start);Elf32_Addrfile_length=file_end-file_page_start;if(file_length!=0){void*seg_addr=mmap((void*)seg_page_start,file_length,PFLAGS_TO_PROT(phdr->p_flags),MAP_FIXED|MAP_PRIVATE,fd_,file_page_start);if(seg_addr==MAP_FAILED){DL_ERR("couldn't map \"%s\" segment %d: %s",name_,i,strerror(errno));returnfalse;}}// if the segment is writable, and does not end on a page boundary,
// zero-fill it until the page limit.
if((phdr->p_flags&PF_W)!=0&&PAGE_OFFSET(seg_file_end)>0){memset((void*)seg_file_end,0,PAGE_SIZE-PAGE_OFFSET(seg_file_end));}seg_file_end=PAGE_END(seg_file_end);// seg_file_end is now the first page address after the file
// content. If seg_end is larger, we need to zero anything
// between them. This is done by using a private anonymous
// map for all extra pages.
if(seg_page_end>seg_file_end){void*zeromap=mmap((void*)seg_file_end,seg_page_end-seg_file_end,PFLAGS_TO_PROT(phdr->p_flags),MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,-1,0);if(zeromap==MAP_FAILED){DL_ERR("couldn't zero fill \"%s\" gap: %s",name_,strerror(errno));returnfalse;}}}returntrue;}
//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker_phdr.cpp
boolElfReader::FindPhdr(){constElf32_Phdr*phdr_limit=phdr_table_+phdr_num_;// If there is a PT_PHDR, use it directly.
for(constElf32_Phdr*phdr=phdr_table_;phdr<phdr_limit;++phdr){if(phdr->p_type==PT_PHDR){returnCheckPhdr(load_bias_+phdr->p_vaddr);}}// Otherwise, check the first loadable segment. If its file offset
// is 0, it starts with the ELF header, and we can trivially find the
// loaded program header from it.
for(constElf32_Phdr*phdr=phdr_table_;phdr<phdr_limit;++phdr){if(phdr->p_type==PT_LOAD){if(phdr->p_offset==0){Elf32_Addrelf_addr=load_bias_+phdr->p_vaddr;constElf32_Ehdr*ehdr=(constElf32_Ehdr*)(void*)elf_addr;Elf32_Addroffset=ehdr->e_phoff;returnCheckPhdr((Elf32_Addr)ehdr+offset);}break;}}DL_ERR("can't find loaded phdr for \"%s\"",name_);returnfalse;}
//http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker.cpp
staticboolsoinfo_link_image(soinfo*si){//----------------------------------
// ②对PT_DYNAMIC段中的字段进行遍历,并根据d_tag做不通操作
uint32_tneeded_count=0;for(Elf32_Dyn*d=si->dynamic;d->d_tag!=DT_NULL;++d){DEBUG("d = %p, d[0](tag) = 0x%08x d[1](val) = 0x%08x",d,d->d_tag,d->d_un.d_val);switch(d->d_tag){caseDT_HASH:// 哈希表
si->nbucket=((unsigned*)(base+d->d_un.d_ptr))[0];si->nchain=((unsigned*)(base+d->d_un.d_ptr))[1];si->bucket=(unsigned*)(base+d->d_un.d_ptr+8);si->chain=(unsigned*)(base+d->d_un.d_ptr+8+si->nbucket*4);break;caseDT_STRTAB:// 字符串表
si->strtab=(constchar*)(base+d->d_un.d_ptr);break;caseDT_SYMTAB:// 符号表
si->symtab=(Elf32_Sym*)(base+d->d_un.d_ptr);break;caseDT_PLTREL:if(d->d_un.d_val!=DT_REL){DL_ERR("unsupported DT_RELA in \"%s\"",si->name);returnfalse;}break;caseDT_JMPREL:// PTL重定位表
si->plt_rel=(Elf32_Rel*)(base+d->d_un.d_ptr);break;caseDT_PLTRELSZ:// PTL重定位表大小
si->plt_rel_count=d->d_un.d_val/sizeof(Elf32_Rel);break;caseDT_REL:// 重定位表
si->rel=(Elf32_Rel*)(base+d->d_un.d_ptr);break;caseDT_RELSZ:// 重定位表大小
si->rel_count=d->d_un.d_val/sizeof(Elf32_Rel);break;caseDT_PLTGOT:// GOT全局偏移表,与PLT延迟绑定相关
/* Save this in case we decide to do lazy binding. We don't yet. */si->plt_got=(unsigned*)(base+d->d_un.d_ptr);break;caseDT_DEBUG:// 调试相关
// Set the DT_DEBUG entry to the address of _r_debug for GDB
// if the dynamic table is writable
if((dynamic_flags&PF_W)!=0){d->d_un.d_val=(int)&_r_debug;}break;caseDT_RELA:DL_ERR("unsupported DT_RELA in \"%s\"",si->name);returnfalse;caseDT_INIT:// 初始化函数
si->init_func=reinterpret_cast<linker_function_t>(base+d->d_un.d_ptr);DEBUG("%s constructors (DT_INIT) found at %p",si->name,si->init_func);break;caseDT_FINI:// 析构函数
si->fini_func=reinterpret_cast<linker_function_t>(base+d->d_un.d_ptr);DEBUG("%s destructors (DT_FINI) found at %p",si->name,si->fini_func);break;caseDT_INIT_ARRAY:// init.array 初始化函数列表
si->init_array=reinterpret_cast<linker_function_t*>(base+d->d_un.d_ptr);DEBUG("%s constructors (DT_INIT_ARRAY) found at %p",si->name,si->init_array);break;caseDT_INIT_ARRAYSZ:// init.array 大小
si->init_array_count=((unsigned)d->d_un.d_val)/sizeof(Elf32_Addr);break;caseDT_FINI_ARRAY:// fini.array 析构函数列表
si->fini_array=reinterpret_cast<linker_function_t*>(base+d->d_un.d_ptr);DEBUG("%s destructors (DT_FINI_ARRAY) found at %p",si->name,si->fini_array);break;caseDT_FINI_ARRAYSZ:// fini.array 大小
si->fini_array_count=((unsigned)d->d_un.d_val)/sizeof(Elf32_Addr);break;caseDT_PREINIT_ARRAY:// 初始化函数,大多只出现在可执行文件中,在so中忽略
si->preinit_array=reinterpret_cast<linker_function_t*>(base+d->d_un.d_ptr);DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p",si->name,si->preinit_array);break;caseDT_PREINIT_ARRAYSZ:// 初始化函数列表大小
si->preinit_array_count=((unsigned)d->d_un.d_val)/sizeof(Elf32_Addr);break;caseDT_TEXTREL:si->has_text_relocations=true;break;caseDT_SYMBOLIC:si->has_DT_SYMBOLIC=true;break;caseDT_NEEDED:// 当前so的依赖,仅做计数操作
++needed_count;break;//----------------------------------
}}//----------------------------------
soinfo**needed=(soinfo**)alloca((1+needed_count)*sizeof(soinfo*));soinfo**pneeded=needed;// ③再次遍历PT_DYNAMIC段,进行so依赖库加载
for(Elf32_Dyn*d=si->dynamic;d->d_tag!=DT_NULL;++d){if(d->d_tag==DT_NEEDED){constchar*library_name=si->strtab+d->d_un.d_val;DEBUG("%s needs %s",si->name,library_name);soinfo*lsi=find_library(library_name);if(lsi==NULL){strlcpy(tmp_err_buf,linker_get_error_buffer(),sizeof(tmp_err_buf));DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",library_name,si->name,tmp_err_buf);returnfalse;}*pneeded++=lsi;}}*pneeded=NULL;//----------------------------------
// ④根据PTL重定位表或者重定位表来处理重定位
if(si->plt_rel!=NULL){DEBUG("[ relocating %s plt ]",si->name);if(soinfo_relocate(si,si->plt_rel,si->plt_rel_count,needed)){returnfalse;}}if(si->rel!=NULL){DEBUG("[ relocating %s ]",si->name);if(soinfo_relocate(si,si->rel,si->rel_count,needed)){returnfalse;}}//----------------------------------
// ⑤设置so的链接标志
si->flags|=FLAG_LINKED;DEBUG("[ finished linking %s ]",si->name);if(si->has_text_relocations){/* All relocations are done, we can protect our segments back to
* read-only. */if(phdr_table_protect_segments(si->phdr,si->phnum,si->load_bias)<0){DL_ERR("can't protect segments for \"%s\": %s",si->name,strerror(errno));returnfalse;}}/* We can also turn on GNU RELRO protection */if(phdr_table_protect_gnu_relro(si->phdr,si->phnum,si->load_bias)<0){DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",si->name,strerror(errno));returnfalse;}notify_gdb_of_load(si);returntrue;}