继续上一篇说到的,在load_library()函数中,在so文件加载完以后,接着就会调用soinfo_alloc函数为so分配soinfo,Linker 为 每个 SO 维护了一个soinfo结构,调用 dlopen时,返回的句柄其实就是一个指向该 SO 的 soinfo 指针。soinfo 保存了 SO 加载链接以及运行期间所需的各类信息.接下来就看soinfo_alloc这个函数:
static soinfo* soinfo_alloc(const char* name) {
if (strlen(name) >= <strong>SOINFO_NAME_LEN</strong>) {
DL_ERR("library name \"%s\" too long", name);
return NULL;
}
if (!ensure_free_list_non_empty()) {
DL_ERR("out of memory when loading \"%s\"", name);
return NULL;
}
// Take the head element off the free list.
soinfo* si = gSoInfoFreeList;
gSoInfoFreeList = gSoInfoFreeList->next;
// Initialize the new element.
memset(si, 0, sizeof(soinfo));
strlcpy(si->name, name, sizeof(si->name));
sonext->next = si;
sonext = si;
TRACE("name %s: allocated soinfo @ %p", name, si);
return si;
}
为加载进内存的so分配空间,并加到soinfo的链表中。
接着看load_library函数剩余部分
static soinfo* load_library(const char* name) {
// Open the file.
int fd = open_library(name);
if (fd == -1) {
DL_ERR("library \"%s\" not found", name);
return NULL;
}
// Read the ELF header and load the segments.
ElfReader elf_reader(name, fd);
if (!elf_reader.Load()) {
return NULL;
}
const char* bname = strrchr(name, '/');
soinfo* si = <strong>soinfo_alloc</strong>(bname ? bname + 1 : name);
if (si == NULL) {
return NULL;
}
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();
return si;
}
把装载结果更新到soinfo中,接下来看一下soinfo这个结构:
{
public:
char name[SOINFO_NAME_LEN];
const Elf32_Phdr* phdr;
size_t phnum;
Elf32_Addr entry;
Elf32_Addr base;
unsigned size;
uint32_t unused1; // DO NOT USE, maintained for compatibility.
Elf32_Dyn* dynamic;
uint32_t unused2; // DO NOT USE, maintained for compatibility
uint32_t unused3; // DO NOT USE, maintained for compatibility
soinfo* next;
unsigned flags;
const char* strtab;
Elf32_Sym* symtab;
size_t nbucket;
size_t nchain;
unsigned* bucket;
unsigned* chain;
unsigned* plt_got;
Elf32_Rel* plt_rel;
size_t plt_rel_count;
Elf32_Rel* rel;
size_t rel_count;
linker_function_t* preinit_array;
size_t preinit_array_count;
linker_function_t* init_array;
size_t init_array_count;
linker_function_t* fini_array;
size_t fini_array_count;
linker_function_t init_func;
linker_function_t fini_func;
#if defined(ANDROID_ARM_LINKER)
// ARM EABI section used for stack unwinding.
unsigned* ARM_exidx;
size_t ARM_exidx_count;
#elif defined(ANDROID_MIPS_LINKER)
unsigned mips_symtabno;
unsigned mips_local_gotno;
unsigned mips_gotsym;
#endif
size_t ref_count;
link_map_t link_map;
bool constructors_called;
// When you read a virtual address from the ELF file, add this
// value to get the corresponding address in the process' address space.
Elf32_Addr load_bias;
bool has_text_relocations;
bool has_DT_SYMBOLIC;
void CallConstructors();
void CallDestructors();
void CallPreInitConstructors();
private:
void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
void CallFunction(const char* function_name, linker_function_t function);
}
东西似乎有点多,用到时再说。至此关于第二部分分配soinfo结构就完了,下一篇接下来说重头戏关于链接过程。