linker是android的加载器和连接器,同时也是其自身的加载器。
bionic/linker/arch/arm64/begin.S29#include 3031ENTRY(_start)32  mov x0, sp33  bl __linker_init3435  /* linker init returns the _entry address in the main image */36  br x037END(_start)

将堆栈指针sp给r0,然后跳到函数__linker_init,传入的参数就是r0,返回值为程序镜像的入口地址,传给pc,开始正式地执行程序。

调用 __linker_init() 之前,linker 的重定位还没有完成(GOT还不可用),所以任何对外部变量或函数的引用都会产生 segfault,google已对__linker_init作出明确说明:extern "C" ElfW(Addr) __linker_init(void* raw_args);
二、__linker_init()实现
__linker_init()code位置,bionic/linker/linker_main.cpp
其第一步就是对参数进行解析,KernelArgumentBlock是一个类
KernelArgumentBlock args(raw_args);
其构造函数如下,可见主要是从参数解析出argc、argv、envp、auxv等参数,最终这几个参数会在linker加载完毕后赋值给linker的几个全局变量
35  KernelArgumentBlock(void* raw_args) {36    uintptr_t* args = reinterpret_cast(raw_args);37    argc = static_cast(*args);38    argv = reinterpret_cast(args + 1);39    envp = argv + argc + 1;4041    // 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) {45      ++p;46    }47    ++p; // Skip the NULL itself.4849    auxv = reinterpret_cast(p);50  }
//最后会赋值给几个全局变量
535  g_argc = args.argc;536  g_argv = args.argv;537  g_envp = args.envp;
然后,获取linker的入口、elf header、程序头(program header,elf文件的一个段)地址
490  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);491  ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr);492  ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff);
//初始化soinfo对象成员,其描述了so库的
494  soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);495496  linker_so.base = linker_addr;//linker地址497  linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);//获取linker镜像大小,仅计算load字段,且页对齐,也可以readelf -S linker查看498  linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);//linker内存中的加载虚拟地址499  linker_so.dynamic = nullptr;500  linker_so.phdr = phdr;501  linker_so.phnum = elf_hdr->e_phnum;502  linker_so.set_linker_flag(); //flags!=FLAG_LINKER
  //调用phdr_table_get_dynamic_section函数,获取PT_DYNAMIC段,然后解析并保存相关内容,包括了init_array、string表、system table表等等505  if (!linker_so.prelink_image()) __linker_cannot_link(args.argv[0]);     //完成linker的重定位,重点是里面调用的relocate方法,根据.rela.dyn 、.rela.plt的信息修改got表中的内容513  if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args.argv[0]);524  //主要初始化pthread_internal_t对象main_thread的各个成员525  __libc_init_main_thread(args);526527  // We didn't protect the linker's RELRO pages in link_image because we528  // couldn't make system calls on x86 at that point, but we can now...529  if (!linker_so.protect_relro()) __linker_cannot_link(args.argv[0]);530531  // 初始化libc的静态全局变量,如 __libc_globals、__libc_auxv等532  __libc_init_globals(args);539  //调用linker的构造方法,初始化linker的全局变量,即执行init段540  linker_so.call_constructors();...... //主要是new 一个soinfo对象,并初始化成员,kLinkerPath即路径/system/bin/linker,并保存在全局对象g_default_namespace的一个成员Vector中558  sonext = solist = get_libdl_info(kLinkerPath);559  g_default_namespace.add_soinfo(solist);560561  // linker已重定位完毕,准备执行563  args.abort_message_ptr = &g_abort_message;564  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);568  //返回要执行的汇编地址569  return start_address;570}


三、prelink_image()的实现
2822bool soinfo::prelink_image() {2823  //提取动态节(dynamic section)2825  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);28262827  /* We can't log anything until the linker is relocated */2828  bool relocating_linker = (flags_ & FLAG_LINKER) != 0;......2850  // 从动态节提取有用信息2854  // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html2855  uint32_t needed_count = 0;      //循环遍历每个动态节,并做对应节处理2856  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {2857    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",2858          d, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val));2859    switch (d->d_tag) {2860      case DT_SONAME:2861        // this is parsed after we have strtab initialized (see below).2862        break;28632864      case DT_HASH:2865        nbucket_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[0];2866        nchain_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[1];2867        bucket_ = reinterpret_cast(load_bias + d->d_un.d_ptr + 8);2868        chain_ = reinterpret_cast(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);2869        break;28702871      case DT_GNU_HASH:2872        gnu_nbucket_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[0];2873        // skip symndx2874        gnu_maskwords_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[2];2875        gnu_shift2_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[3];28762877        gnu_bloom_filter_ = reinterpret_cast(load_bias + d->d_un.d_ptr + 16);2878        gnu_bucket_ = reinterpret_cast(gnu_bloom_filter_ + gnu_maskwords_);2879        // amend chain for symndx = header[1]2880        gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -2881            reinterpret_cast(load_bias + d->d_un.d_ptr)[1];28822883        if (!powerof2(gnu_maskwords_)) {2884          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",2885              gnu_maskwords_, get_realpath());2886          return false;2887        }2888        --gnu_maskwords_;28892890        flags_ |= FLAG_GNU_HASH;2891        break;28922893      case DT_STRTAB:2894        strtab_ = reinterpret_cast(load_bias + d->d_un.d_ptr);2895        break;28962897      case DT_STRSZ:2898        strtab_size_ = d->d_un.d_val;2899        break;29002901      case DT_SYMTAB:2902        symtab_ = reinterpret_cast(load_bias + d->d_un.d_ptr);2903        break;29042905      case DT_SYMENT:2906        if (d->d_un.d_val != sizeof(ElfW(Sym))) {2907          DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",2908              static_cast(d->d_un.d_val), get_realpath());2909          return false;2910        }2911        break;29122913      case DT_PLTREL:2914#if defined(USE_RELA)2915        if (d->d_un.d_val != DT_RELA) {2916          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());2917          return false;2918        }2919#else2920        if (d->d_un.d_val != DT_REL) {2921          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());2922          return false;2923        }2924#endif2925        break;29262927      case DT_JMPREL:2928#if defined(USE_RELA)2929        plt_rela_ = reinterpret_cast(load_bias + d->d_un.d_ptr);2930#else2931        plt_rel_ = reinterpret_cast(load_bias + d->d_un.d_ptr);2932#endif2933        break;29342935      case DT_PLTRELSZ:2936#if defined(USE_RELA)2937        plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));2938#else2939        plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));2940#endif2941        break;2951      case DT_DEBUG:2952        // Set the DT_DEBUG entry to the address of _r_debug for GDB2953        // if the dynamic table is writable2963        break;2965      case DT_RELA:2966        rela_ = reinterpret_cast(load_bias + d->d_un.d_ptr);2967        break;29682969      case DT_RELASZ:2970        rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));2971        break;29722973      case DT_ANDROID_RELA:2974        android_relocs_ = reinterpret_cast(load_bias + d->d_un.d_ptr);2975        break;29762977      case DT_ANDROID_RELASZ:2978        android_relocs_size_ = d->d_un.d_val;2979        break;29802981      case DT_ANDROID_REL:2982        DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());2983        return false;29842985      case DT_ANDROID_RELSZ:2986        DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());2987        return false;29882989      case DT_RELAENT:2990        if (d->d_un.d_val != sizeof(ElfW(Rela))) {2991          DL_ERR("invalid DT_RELAENT: %zd", static_cast(d->d_un.d_val));2992          return false;2993        }2994        break;29952996      // ignored (see DT_RELCOUNT comments for details)2997      case DT_RELACOUNT:2998        break;29993000      case DT_REL:3001        DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());3002        return false;30033004      case DT_RELSZ:3005        DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());3006        return false;3057      case DT_INIT:3058        init_func_ = reinterpret_cast(load_bias + d->d_un.d_ptr);3059        DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);3060        break;30613062      case DT_FINI:3063        fini_func_ = reinterpret_cast(load_bias + d->d_un.d_ptr);3064        DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);3065        break;30663067      case DT_INIT_ARRAY:3068        init_array_ = reinterpret_cast(load_bias + d->d_un.d_ptr);3069        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);3070        break;30713072      case DT_INIT_ARRAYSZ:3073        init_array_count_ = static_cast(d->d_un.d_val) / sizeof(ElfW(Addr));3074        break;30753076      case DT_FINI_ARRAY:3077        fini_array_ = reinterpret_cast(load_bias + d->d_un.d_ptr);3078        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);3079        break;30803081      case DT_FINI_ARRAYSZ:3082        fini_array_count_ = static_cast(d->d_un.d_val) / sizeof(ElfW(Addr));3083        break;30843085      case DT_PREINIT_ARRAY:3086        preinit_array_ = reinterpret_cast(load_bias + d->d_un.d_ptr);3087        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);3088        break;30893090      case DT_PREINIT_ARRAYSZ:3091        preinit_array_count_ = static_cast(d->d_un.d_val) / sizeof(ElfW(Addr));3092        break;30933094      case DT_TEXTREL:3103      case DT_SYMBOLIC:3104        has_DT_SYMBOLIC = true;3105        break;31063107      case DT_NEEDED:3108        ++needed_count;3109        break;31103111      case DT_FLAGS:3112        if (d->d_un.d_val & DF_TEXTREL) {3113#if defined(__LP64__)3114          DL_ERR("\"%s\" has text relocations", get_realpath());3115          return false;3116#else3117          has_text_relocations = true;3118#endif3119        }3120        if (d->d_un.d_val & DF_SYMBOLIC) {3121          has_DT_SYMBOLIC = true;3122        }3123        break;31243125      case DT_FLAGS_1:3126        set_dt_flags_1(d->d_un.d_val);31273128        if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {3129          DL_WARN("\"%s\" has unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast(d->d_un.d_val));3130        }3131        break;3167      // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"3168      case DT_BIND_NOW:3169        break;31703171      case DT_VERSYM:3172        versym_ = reinterpret_cast(load_bias + d->d_un.d_ptr);3173        break;31743175      case DT_VERDEF:3176        verdef_ptr_ = load_bias + d->d_un.d_ptr;3177        break;3178      case DT_VERDEFNUM:3179        verdef_cnt_ = d->d_un.d_val;3180        break;31813182      case DT_VERNEED:3183        verneed_ptr_ = load_bias + d->d_un.d_ptr;3184        break;31853186      case DT_VERNEEDNUM:3187        verneed_cnt_ = d->d_un.d_val;3188        break;31893190      case DT_RUNPATH:3191        // this is parsed after we have strtab initialized (see below).3192        break;31933194      default:3195        if (!relocating_linker) {3196          DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),3197              reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val));3198        }3199        break;3200    }3201  }3212  // Sanity checks.3213  if (relocating_linker && needed_count != 0) {3214    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");3215    return false;3216  }3217  if (nbucket_ == 0 && gnu_nbucket_ == 0) {3218    DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "3219        "(new hash type from the future?)", get_realpath());3220    return false;3221  }3222  if (strtab_ == 0) {3223    DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());3224    return false;3225  }3226  if (symtab_ == 0) {3227    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());3228    return false;3229  }32303231  // second pass - parse entries relying on strtab3232  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {3233    switch (d->d_tag) {3234      case DT_SONAME:3235        set_soname(get_string(d->d_un.d_val));3236        break;3237      case DT_RUNPATH:3238        set_dt_runpath(get_string(d->d_un.d_val));3239        break;3240    }3241  }32423243  // Before M release linker was using basename in place of soname.3244  // In the case when dt_soname is absent some apps stop working3245  // because they can't find dt_needed library by soname.3246  // This workaround should keep them working. (applies only3247  // for apps targeting sdk version < M). Make an exception for3248  // the main executable and linker; they do not need to have dt_soname3249  if (soname_ == nullptr &&3250      this != solist_get_somain() &&3251      (flags_ & FLAG_LINKER) == 0 &&3252      get_application_target_sdk_version() < __ANDROID_API_M__) {3253    soname_ = basename(realpath_.c_str());3254    DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",3255        get_realpath(), soname_);3256    // Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI3257  }3258  return true;3259}

四、link_image实现
3261bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,3262                        const android_dlextinfo* extinfo) {32633264  local_group_root_ = local_group.front(); //当前是个空list3265  if (local_group_root_ == nullptr) {3266    local_group_root_ = this;3267  }32683269  if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) { //已经设置FLAG_LINKER3270    target_sdk_version_ = get_application_target_sdk_version();3271  }32723273  VersionTracker version_tracker;32743275  if (!version_tracker.init(this)) {3276    return false;3277  }......3299  if (android_relocs_ != nullptr) { //android_relocs_在prelink_image()中设置,动态节有DT_ANDROID_REL才会设置3300    // check signature3301    if (android_relocs_size_ > 3 &&3302        android_relocs_[0] == 'A' &&3303        android_relocs_[1] == 'P' &&3304        android_relocs_[2] == 'S' &&3305        android_relocs_[3] == '2') {3306      DEBUG("[ android relocating %s ]", get_realpath());33073308      bool relocated = false;3309      const uint8_t* packed_relocs = android_relocs_ + 4;3310      const size_t packed_relocs_size = android_relocs_size_ - 4;33113312      relocated = relocate(3313          version_tracker,3314          packed_reloc_iterator(3315            sleb128_decoder(packed_relocs, packed_relocs_size)),3316          global_group, local_group);//调用relocate完成重定位relocs33173318      if (!relocated) {3319        return false;3320      }3321    } else {3322      DL_ERR("bad android relocation header.");3323      return false;3324    }3325  }3328  if (rela_ != nullptr) { //rela_在prelink_image()中设置,动态节有DT_RELA才会设置3329    DEBUG("[ relocating %s ]", get_realpath());3330    if (!relocate(version_tracker,   //调用relocate完成重定位rela_3331            plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {3332      return false;3333    }3334  }3335  if (plt_rela_ != nullptr) {//plt_rela_在prelink_image()中设置,动态节有DT_RELA才会设置3336    DEBUG("[ relocating %s plt ]", get_realpath());3337    if (!relocate(version_tracker,   //调用relocate完成重定位plt_rela_3338            plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {3339      return false;3340    }3341  }......3378  // We can also turn on GNU RELRO protection if we're not linking the dynamic linker3379  // itself --- it can't make system calls yet, and will have to call protect_relro later.3380  if (!is_linker() && !protect_relro()) {//当前是linker3381    return false;3382  }33833384  /* Handle serializing/sharing the RELRO segment */3385  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {3386    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,3387                                       extinfo->relro_fd) < 0) {3388      DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",3389             get_realpath(), strerror(errno));3390      return false;3391    }3392  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {3393    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,3394                                 extinfo->relro_fd) < 0) {3395      DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",3396             get_realpath(), strerror(errno));3397      return false;3398    }3399  }34003401  notify_gdb_of_load(this);//linker不支持gdb debug3402  return true;3403}可见link_image方法也主要是调用了relocate完成重定位。


五、__linker_init_post_relocation()是完成重定位后的一些处理,例如注册信号处理函数。
211static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {220  __libc_init_AT_SECURE(args);221222  //初始化系统属性223  __system_properties_init(); // may use 'environ'224225  // Register the debuggerd signal handler.226#ifdef __ANDROID__227  debuggerd_callbacks_t callbacks = {228    .get_abort_message = []() {229      return g_abort_message;230    },231    .post_dump = ¬ify_gdb_of_libraries,232  };233  debuggerd_init(&callbacks);  //很重要注册了7个信号处理函数234#endif235236  g_linker_logger.ResetState();237238  // Get a few environment variables.239  const char* LD_DEBUG = getenv("LD_DEBUG");240  if (LD_DEBUG != nullptr) {241    g_ld_debug_verbosity = atoi(LD_DEBUG);242  }......254  if (!getauxval(AT_SECURE)) {255    ldpath_env = getenv("LD_LIBRARY_PATH");256    if (ldpath_env != nullptr) {257      INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env);258    }259    ldpreload_env = getenv("LD_PRELOAD");260    if (ldpreload_env != nullptr) {261      INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env);262    }263  }264265  struct stat file_stat;269  if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {270    __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));271  }272273  const char* executable_path = get_executable_path();274  soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);275  if (si == nullptr) {276    __libc_fatal("Couldn't allocate soinfo: out of memory?");277  }278279  /* bootstrap the link map, the main exe always needs to be first */280  si->set_main_executable();281  link_map* map = &(si->link_map_head);282283  // Register the main executable and the linker upfront to have284  // gdb aware of them before loading the rest of the dependency285  // tree.286  map->l_addr = 0;287  map->l_name = const_cast(executable_path);288  insert_link_map_into_debug_map(map);289  init_linker_info_for_gdb(linker_base, kLinkerPath);290291  // Extract information passed from the kernel.292  si->phdr = reinterpret_cast(args.getauxval(AT_PHDR));293  si->phnum = args.getauxval(AT_PHNUM);294295  /* Compute the value of si->base. We can't rely on the fact that296   * the first entry is the PHDR because this will not be true297   * for certain executables (e.g. some in the NDK unit test suite)298   */299  si->base = 0;300  si->size = phdr_table_get_load_size(si->phdr, si->phnum);301  si->load_bias = 0;302  for (size_t i = 0; i < si->phnum; ++i) {303    if (si->phdr[i].p_type == PT_PHDR) {304      si->load_bias = reinterpret_cast(si->phdr) - si->phdr[i].p_vaddr;305      si->base = reinterpret_cast(si->phdr) - si->phdr[i].p_offset;306      break;307    }308  }309  si->dynamic = nullptr;310311  ElfW(Ehdr)* elf_hdr = reinterpret_cast(si->base);312......329  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).330  parse_LD_LIBRARY_PATH(ldpath_env);331  parse_LD_PRELOAD(ldpreload_env);332333  somain = si;334335  init_default_namespace(executable_path);336337  if (!si->prelink_image()) {338    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());339  }340341  // add somain to global group342  si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);343344  // Load ld_preloads and dependencies.345  std::vector needed_library_name_list;346  size_t ld_preloads_count = 0;347348  for (const auto& ld_preload_name : g_ld_preload_names) {349    needed_library_name_list.push_back(ld_preload_name.c_str());350    ++ld_preloads_count;351  }352353  for_each_dt_needed(si, [&](const char* name) {354    needed_library_name_list.push_back(name);355  });356 //找出依赖库,并调用find_libraries357  const char** needed_library_names = &needed_library_name_list[0];358  size_t needed_libraries_count = needed_library_name_list.size();359360  if (needed_libraries_count > 0 &&361      !find_libraries(&g_default_namespace,362                      si,363                      needed_library_names,364                      needed_libraries_count,365                      nullptr,366                      &g_ld_preloads,367                      ld_preloads_count,368                      RTLD_GLOBAL,369                      nullptr,370                      true /* add_as_children */,371                      true /* search_linked_namespaces */)) {372    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());373  } else if (needed_libraries_count == 0) {374    if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {375      __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());376    }377    si->increment_ref_count();378  }379380  add_vdso(args);381382  if (!get_cfi_shadow()->InitialLinkDone(solist)) {383    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());384  }385386  si->call_pre_init_constructors();387388  /* After the prelink_image, the si->load_bias is initialized.389   * For so lib, the map->l_addr will be updated in notify_gdb_of_load.390   * We need to update this value for so exe here. So Unwind_Backtrace391   * for some arch like x86 could work correctly within so exe.392   */393  map->l_addr = si->load_bias;394  si->call_constructors();395......437  ElfW(Addr) entry = args.getauxval(AT_ENTRY);//程序执行入口438  TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast(entry));439  return entry;440}

参考:
https://blog.csdn.net/xiongtiancheng/article/details/78786389
https://www.cnblogs.com/ilocker/p/4540797.html
https://blog.csdn.net/wl429585967/article/details/51019906
https://blog.csdn.net/suningning/article/details/61429932

更多相关文章

  1. Android学习(十) SQLite 基于内置函数的操作方式
  2. android的webview调用javascript函数并得到返回值
  3. 可动态布局的Android抽屉之完整篇
  4. Android 数据查询query函数参数解析
  5. android中的类加载和静态成员变量的初始化
  6. android动态申请拍照获取照片权限
  7. Android中显示gif动态图片
  8. Android 禁止屏幕旋转 & 屏幕旋转不刷新 Activity & 动态更改屏

随机推荐

  1. Android 的 Recovery 模式分析
  2. doubango tinyDEMO 编译
  3. Android中关于Audio库的知识
  4. android实现点击空白处,软键盘消失事件
  5. Android进程间通信(IPC)
  6. 2011.07.01——— android GridView 长按
  7. Android - ToDoList 详解
  8. Android布局动画之animateLayoutChanges
  9. Android(安卓)自定义Application
  10. Android(安卓)SlidingMenu实现沉浸式状态