android inker和Exe加载 : linker_main函数解释

Posted malihom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android inker和Exe加载 : linker_main函数解释相关的知识,希望对你有一定的参考价值。

Linker和Exe加载 : linker_main函数解释

linker main执行的任务前,在linker重定位,libc初始化,主线程初始化等一些列操作完成后,进程的用户空间已经具备动态链接的能力,开始可以动态链接exe相关的依赖了。

linker main源码

static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load) {
  ProtectedDataGuard guard;

#if TIMING
  struct timeval t0, t1;
  gettimeofday(&t0, 0);
#endif

  // Sanitize the environment.
  //主要是stdin等重定向到/dev/null,排除掉非法/不安全的环境变量
  __libc_init_AT_SECURE(args.envp);

  // Initialize system properties
  //系统属性初始化
  __system_properties_init(); // may use 'environ'

  // Register the debuggerd signal handler.
  linker_debuggerd_init();

  g_linker_logger.ResetState();

  // Get a few environment variables.
  const char* LD_DEBUG = getenv("LD_DEBUG");
  if (LD_DEBUG != nullptr) {
    g_ld_debug_verbosity = atoi(LD_DEBUG);
  }

#if defined(__LP64__)
  INFO("[ android dynamic linker (64-bit) ]");
#else
  INFO("[ Android dynamic linker (32-bit) ]");
#endif

  // These should have been sanitized by __libc_init_AT_SECURE, but the test
  // doesn't cost us anything.
  const char* ldpath_env = nullptr;
  const char* ldpreload_env = nullptr;
  if (!getauxval(AT_SECURE)) {
    ldpath_env = getenv("LD_LIBRARY_PATH");
    if (ldpath_env != nullptr) {
      INFO("[ LD_LIBRARY_PATH set to \\"%s\\" ]", ldpath_env);
    }
    ldpreload_env = getenv("LD_PRELOAD");
    if (ldpreload_env != nullptr) {
      INFO("[ LD_PRELOAD set to \\"%s\\" ]", ldpreload_env);
    }
  }

  //动态加载exe elf,由于exe实际上已经被内核加载了,这里仅仅是读取elf的信息和mmap文件到用户空间,而没有加载exe的依赖和进行相关的重定位
  const ExecutableInfo exe_info = exe_to_load ? load_executable(exe_to_load) :
                                                get_executable_info();

  INFO("[ Linking executable \\"%s\\" ]", exe_info.path.c_str());

  //初始化代表exe elf的soinfo
  // Initialize the main exe's soinfo.
  soinfo* si = soinfo_alloc(&g_default_namespace,
                            exe_info.path.c_str(), &exe_info.file_stat,
                            0, RTLD_GLOBAL);
  somain = si;
  si->phdr = exe_info.phdr;
  si->phnum = exe_info.phdr_count;
  get_elf_base_from_phdr(si->phdr, si->phnum, &si->base, &si->load_bias);
  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
  si->dynamic = nullptr;
  si->set_main_executable();
  init_link_map_head(*si);

  //设置exe bss的vma的名字
  set_bss_vma_name(si);

  //查找exe elf对应的.interp段(对于app_process64来说,就是linker64)
  // Use the executable's PT_INTERP string as the solinker filename in the
  // dynamic linker's module list. gdb reads both PT_INTERP and the module list,
  // and if the paths for the linker are different, gdb will report that the
  // PT_INTERP linker path was unloaded once the module list is initialized.
  // There are three situations to handle:
  //  - the APEX linker (/system/bin/linker[64] -> /apex/.../linker[64])
  //  - the ASAN linker (/system/bin/linker_asan[64] -> /apex/.../linker[64])
  //  - the bootstrap linker (/system/bin/bootstrap/linker[64])
  const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
                                                       somain->load_bias);
  if (interp == nullptr) {
    // This case can happen if the linker attempts to execute itself
    // (e.g. "linker64 /system/bin/linker64").
    interp = kFallbackLinkerPath;
  }
  solinker->set_realpath(interp);
  init_link_map_head(*solinker);

  //gdb相关
  // Register the main executable and the linker upfront to have
  // gdb aware of them before loading the rest of the dependency
  // tree.
  //
  // gdb expects the linker to be in the debug shared object list.
  // Without this, gdb has trouble locating the linker's ".text"
  // and ".plt" sections. Gdb could also potentially use this to
  // relocate the offset of our exported 'rtld_db_dlactivity' symbol.
  //
  insert_link_map_into_debug_map(&si->link_map_head);
  insert_link_map_into_debug_map(&solinker->link_map_head);

  //vdso相关,暂且不表
  add_vdso();

  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);

  // We haven't supported non-PIE since Lollipop for security reasons.
  if (elf_hdr->e_type != ET_DYN) {
    // We don't use async_safe_fatal here because we don't want a tombstone:
    // even after several years we still find ourselves on app compatibility
    // investigations because some app's trying to launch an executable that
    // hasn't worked in at least three years, and we've "helpfully" dropped a
    // tombstone for them. The tombstone never provided any detail relevant to
    // fixing the problem anyway, and the utility of drawing extra attention
    // to the problem is non-existent at this late date.
    async_safe_format_fd(STDERR_FILENO,
                         "\\"%s\\": error: Android 5.0 and later only support "
                         "position-independent executables (-fPIE).\\n",
                         g_argv[0]);
    _exit(EXIT_FAILURE);
  }

  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
  parse_LD_LIBRARY_PATH(ldpath_env);//解释//LD_LIBRARY_PATH
  parse_LD_PRELOAD(ldpreload_env);//解释LD_PRELOAD

  //android namespace相关:参考:https://source.android.com/devices/architecture/vndk/linker-namespace
  std::vector<android_namespace_t*> namespaces = init_default_namespaces(exe_info.path.c_str());

  //exe文件解释.dynamic段
  if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);

  // add somain to global group
  si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
  // ... and add it to all other linked namespaces
  for (auto linked_ns : namespaces) {
    if (linked_ns != &g_default_namespace) {
      linked_ns->add_soinfo(somain);
      somain->add_secondary_namespace(linked_ns);
    }
  }

  //设置exe相关的tls,使其注册到linker全局的g_tls_modules
  linker_setup_exe_static_tls(g_argv[0]);

  //加载所有的ld_preloads和依赖,link全部的so
  // Load ld_preloads and dependencies.
  std::vector<const char*> needed_library_name_list;
  size_t ld_preloads_count = 0;

  for (const auto& ld_preload_name : g_ld_preload_names) {
    needed_library_name_list.push_back(ld_preload_name.c_str());
    ++ld_preloads_count;
  }

  for_each_dt_needed(si, [&](const char* name) {
    needed_library_name_list.push_back(name);
  });

  const char** needed_library_names = &needed_library_name_list[0];
  size_t needed_libraries_count = needed_library_name_list.size();

  if (needed_libraries_count > 0 &&
      !find_libraries(&g_default_namespace,
                      si,
                      needed_library_names,
                      needed_libraries_count,
                      nullptr,
                      &g_ld_preloads,
                      ld_preloads_count,
                      RTLD_GLOBAL,
                      nullptr,
                      true /* add_as_children */,
                      true /* search_linked_namespaces */,
                      &namespaces)) {
    __linker_cannot_link(g_argv[0]);
  } else if (needed_libraries_count == 0) {
    if (!si->link_image(SymbolLookupList(si), si, nullptr, nullptr)) {
      __linker_cannot_link(g_argv[0]);
    }
    si->increment_ref_count();
  }

  //完成tls相关工作(内部知识round up一下offset)
  linker_finalize_static_tls();
  //完成main thread的初始化,参考前面文章
  __libc_init_main_thread_final();

  if (!get_cfi_shadow()->InitialLinkDone(solist)) __linker_cannot_link(g_argv[0]);

  //执行exe文件的DT_PREINIT_ARRAY、DT_INIT、DT_INIT_ARRAY段内容
  si->call_pre_init_constructors();
  si->call_constructors();

#if TIMING
  gettimeofday(&t1, nullptr);
  PRINT("LINKER TIME: %s: %d microseconds", g_argv[0],
        static_cast<int>(((static_cast<long long>(t1.tv_sec) * 1000000LL) +
                          static_cast<long long>(t1.tv_usec)) -
                         ((static_cast<long long>(t0.tv_sec) * 1000000LL) +
                          static_cast<long long>(t0.tv_usec))));
#endif
#if STATS
  print_linker_stats();
#endif
#if TIMING || STATS
  fflush(stdout);
#endif

  // We are about to hand control over to the executable loaded.  We don't want
  // to leave dirty pages behind unnecessarily.
  purge_unused_memory();

  //获取exe的入口函数,并返回
  ElfW(Addr) entry = exe_info.entry_point;
  TRACE("[ Ready to execute \\"%s\\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
  return entry;
}

linker_main主要作用就是,初始化系统属性,加载和重定位exe文件的preloads和依赖,并执行自身的初始化函数,并最终返回其入口函数。

以上是关于android inker和Exe加载 : linker_main函数解释的主要内容,如果未能解决你的问题,请参考以下文章

自己的微信小程序学习笔记——第三方UI库Lin-Ui的加载及使用

自己的微信小程序学习笔记——第三方UI库Lin-Ui的加载及使用

自己的微信小程序学习笔记——第三方UI库Lin-Ui的加载及使用

加载失败/usr/local/IonCube/ioncube_loader_lin_5.3.so

Android Studio - No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-lin

Android Studio Cmake:“C 编译器 clang.exe 无法编译简单的测试程序