通过前一篇的博客,我们知道,在linux kernel加载完可执行程序后,在需要解释器的情况下,返回用户空间时会先跳到解释器的函数中执行,对于android平台而已,就是先跑到_start()函数,然后再跳转到__linker_init()。
bionic/linker/linker.cpp
extern "C" ElfW(Addr) __linker_init(void* raw_args) {
4431 KernelArgumentBlock args(raw_args);
4432
4433 ElfW(Addr) linker_addr = args.getauxval(AT_BASE); //interp_load_addr 解释器 加载到内存的地址
4434 ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); //可执行程序的入口地址
4435 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); //linker文件的起始位置 Elf64_Ehdr
4436 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); // linker中的程序头表 Elf64_Phdr
4437
4438 soinfo linker_so(nullptr, nullptr, nullptr, 0, 0); //soinfo 一个很重要的结构体
...
4452
4453 linker_so.base = linker_addr;
4454 linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); //加载的PT_LOAD段的大小
4455 linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); //类似于一个加载的偏移
4456 linker_so.dynamic = nullptr;
4457 linker_so.phdr = phdr; //
4458 linker_so.phnum = elf_hdr->e_phnum; //
4459 linker_so.set_linker_flag();
4460
4461 // Prelink the linker so we can access linker globals.
4462 if (!linker_so.prelink_image()) __linker_cannot_link(args); //解析(遍历)PT_DYNAMIC 段(.dynamic节)里面的内容
...
4470 if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args); //根据.rela.dyn .rela.plt进行重定位
...
4481 // Initialize the main thread (including TLS, so system calls really work).
4482 __libc_init_main_thread(args);
4483
4484 // We didn't protect the linker's RELRO pages in link_image because we
4485 // couldn't make system calls on x86 at that point, but we can now...
4486 if (!linker_so.protect_relro()) __linker_cannot_link(args); //将PT_GNU_RELRO段指向的内存地址通过mprotoct函数设置为PROT_READ
4487
4488 // Initialize the linker's static libc's globals
4489 __libc_init_globals(args);
4490
4491 // Initialize the linker's own global variables
4492 linker_so.call_constructors();
4493
4494 // Initialize static variables. Note that in order to
4495 // get correct libdl_info we need to call constructors
4496 // before get_libdl_info().
4497 solist = get_libdl_info();
4498 sonext = get_libdl_info();
4499 g_default_namespace.add_soinfo(get_libdl_info());
4500
4501 // We have successfully fixed our own relocations. It's safe to run
4502 // the main part of the linker now.
4503 args.abort_message_ptr = &g_abort_message;
4504 ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
4505
4506 INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
4507
4508 // Return the address that the calling assembly stub should jump to.
4509 return start_address;
4510 }
KernelArgumentBlock 这个类是用来解析从kernel 拷贝过来的参数
bionic/libc/private/KernelArgumentBlock.h
/* 根据前一篇博客的分析,kernel拷贝参数到用户空间的分布如下
* | 0 |
* | 0 |
* | elf_info[valn] |
* | elf_info[id0] |
* | ... |
* | elf_info[val0] |
* | elf_info[id0] |
* | 0 |
* | envn |
* | ... |
* | env0 |
* | 0 |
* | argn |
* | .... |
* | arg0 |
* raw_args -> | argc |
*/
class KernelArgumentBlock {
34 public:
35 KernelArgumentBlock(void* raw_args) {
36 uintptr_t* args = reinterpret_cast<uintptr_t*>(raw_args);
37 argc = static_cast<int>(*args); //传递的参数个数,不包括环境变量参数,也就是上面的argc
38 argv = reinterpret_cast<char**>(args + 1); //指向arg0 的位置
39 envp = argv + argc + 1; //加上argc,再加1,就指到env0 的位置
40
41 // Skip over all environment variable definitions to find the aux vector.
42 // The end of the environment block is marked by a NULL pointer.
43 char** p = envp;
44 while (*p != NULL) { //等于NULL,就指到envn 后面 0的位置
45 ++p;
46 }
47 ++p; // Skip the NULL itself.//再加1就指到elf_info[id0]位置
48
49 auxv = reinterpret_cast<ElfW(auxv_t)*>(p);
50 }
51
52 // Similar to ::getauxval but doesn't require the libc global variables to be set up,
53 // so it's safe to call this really early on.
54 unsigned long getauxval(unsigned long type) {
55 for (ElfW(auxv_t)* v = auxv; v->a_type != AT_NULL; ++v) {
56 if (v->a_type == type) {
57 return v->a_un.a_val; //返回a_type 对应的value
58 }
59 }
60 return 0;
61 }
62
63 int argc;
64 char** argv;
65 char** envp;
66 ElfW(auxv_t)* auxv;
67
68 abort_msg_t** abort_message_ptr;
69
70 private:
71 DISALLOW_COPY_AND_ASSIGN(KernelArgumentBlock);
72 };
bionic/linker/linker.cpp
3495 bool soinfo::prelink_image() {
3496 /* Extract dynamic section */
3497 ElfW(Word) dynamic_flags = 0;
3498 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags); //获得linker加载到内存后,.dynamic这个节在内存中的位置
...
/* ElfW(Dyn)对应的数据结构如下
* linux-4.10/include/uapi/linux/elf.h
* typedef struct {
* Elf64_Sxword d_tag; /* entry tag value */
* union {
* Elf64_Xword d_val; //保存值
* Elf64_Addr d_ptr; //保存地址
* } d_un;
* } Elf64_Dyn;
*/
3529 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { //解析(遍历)PT_DYNAMIC 段(.dynamic节)里面的内容
3530 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
3531 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3532 switch (d->d_tag) {
3533 case DT_SONAME:
3534 // this is parsed after we have strtab initialized (see below).
3535 break;
...
3566 case DT_STRTAB: // str table 的位置
3567 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
3568 break;
3569
3570 case DT_STRSZ: //str table 每一项的大小
3571 strtab_size_ = d->d_un.d_val;
3572 break;
3573
3574 case DT_SYMTAB: // sym table 的位置
3575 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
3576 break;
3577
/*
* typedef struct elf64_sym {
* Elf64_Word st_name; //4 by