zoukankan      html  css  js  c++  java
  • Native层和so接口和Java层

    image001

    一、Java层加载so文件

    Android在Java层加载so的接口是System.loadLibrary()逐级调用的过程:

    image002

    image003

           System.loadLibrary()系统源码:

    987    public static void loadLibrary(String libName) {
    988        Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
    989    }

    例程 System.loadLibrary(“xxx”)     [xxx:libname名称]

    Ctrl+左键Loadlibrary跟踪(如果不显示代码,添加SDK目录下sourcesandroid-18文件夹)

    image004

    Ctrl+左键 Runtime.getRuntime().loadLibrary() 中的 loadLibrary跟踪

    image005

    系统重载了loadLibrary()函数察看重载的 loadLibrary()

    其中String libraryName参数为so文件的绝对路径

    356     * Searches for and loads the given shared library using the given ClassLoader.
    357     */
    358    void loadLibrary(String libraryName, ClassLoader loader) {
    359        if (loader != null) {
    360            String filename = loader.findLibrary(libraryName);
    361            if (filename == null) {
    362                // It's not necessarily true that the ClassLoader used
    363                // System.mapLibraryName, but the default setup does, and it's
    364                // misleading to say we didn't find "libMyLibrary.so" when we
    365                // actually searched for "liblibMyLibrary.so.so".
    366                throw new UnsatisfiedLinkError(loader + " couldn't find "" +
    367                                               System.mapLibraryName(libraryName) + """);
    368            }
    369            String error = doLoad(filename, loader);
    370            if (error != null) {
    371                throw new UnsatisfiedLinkError(error);
    372            }
    373            return;
    374        }
    375
    376        String filename = System.mapLibraryName(libraryName);
    377        List<String> candidates = new ArrayList<String>();
    378        String lastError = null;
    379        for (String directory : mLibPaths) {
    380            String candidate = directory + filename;
    381            candidates.add(candidate);
    382
    383            if (IoUtils.canOpenReadOnly(candidate)) {
    384                String error = doLoad(candidate, loader);
    385                if (error == null) {
    386                    return; // We successfully loaded the library. Job done.
    387                }
    388                lastError = error;
    389            }
    390        }
    391
    392        if (lastError != null) {
    393            throw new UnsatisfiedLinkError(lastError);
    394        }
    395        throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
    396    }
    loadLibrary()

    其中doLoad()为加载函数,源码:

    400    private String doLoad(String name, ClassLoader loader) {
    401        // Android apps are forked from the zygote, so they can't have a custom LD_LIBRARY_PATH,
    402        // which means that by default an app's shared library directory isn't on LD_LIBRARY_PATH.
    403
    404        // The PathClassLoader set up by frameworks/base knows the appropriate path, so we can load
    405        // libraries with no dependencies just fine, but an app that has multiple libraries that
    406        // depend on each other needed to load them in most-dependent-first order.
    407
    408        // We added API to Android's dynamic linker so we can update the library path used for
    409        // the currently-running process. We pull the desired path out of the ClassLoader here
    410        // and pass it to nativeLoad so that it can call the private dynamic linker API.
    411
    412        // We didn't just change frameworks/base to update the LD_LIBRARY_PATH once at the
    413        // beginning because multiple apks can run in the same process and third party code can
    414        // use its own BaseDexClassLoader.
    415
    416        // We didn't just add a dlopen_with_custom_LD_LIBRARY_PATH call because we wanted any
    417        // dlopen(3) calls made from a .so's JNI_OnLoad to work too.
    418
    419        // So, find out what the native library search path is for the ClassLoader in question...
    420        String ldLibraryPath = null;
    421        if (loader != null && loader instanceof BaseDexClassLoader) {
    422            ldLibraryPath = ((BaseDexClassLoader) loader).getLdLibraryPath();
    423        }
    424        // nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless
    425        // of how many ClassLoaders are in the system, but dalvik doesn't support synchronized
    426        // internal natives.
    427        synchronized (this) {
    428            return nativeLoad(name, loader, ldLibraryPath);
    429        }
    430    }
    doLoad()

           nativeLoad()用来加载name指向的so文件,nativeLoad()是Runtime类的一个native函数,在native层对应Runtime_nativeLoad()。

    至此Java层的so文件加载跟踪完。根据nativeLoad进入Native层跟踪

    二、nativeload开始 Native层的调用

           Nativeload函数分析图

    image006

    分三个阶段:

    1. so文件加载

    在java_lang_Runtime.cc文件中

    image007

    可知Java层的nativeLoad对应Native层的Runtime_nativeLoad()

    46static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader, jstring javaLdLibraryPath) {
    47  ScopedUtfChars filename(env, javaFilename);
    48  if (filename.c_str() == NULL) {
    49    return NULL;
    50  }
    51
    52  if (javaLdLibraryPath != NULL) {
    53    ScopedUtfChars ldLibraryPath(env, javaLdLibraryPath);
    54    if (ldLibraryPath.c_str() == NULL) {
    55      return NULL;
    56    }
    57    void* sym = dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH");
    58    if (sym != NULL) {
    59      typedef void (*Fn)(const char*);
    60      Fn android_update_LD_LIBRARY_PATH = reinterpret_cast<Fn>(sym);
    61      (*android_update_LD_LIBRARY_PATH)(ldLibraryPath.c_str());
    62    } else {
    63      LOG(ERROR) << "android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!";
    64    }
    65  }
    66
    67  std::string detail;
    68  {
    69    ScopedObjectAccess soa(env);
    70    StackHandleScope<1> hs(soa.Self());
    71    Handle<mirror::ClassLoader> classLoader(
    72        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
    73    JavaVMExt* vm = Runtime::Current()->GetJavaVM();
            // 调用JavaVMExt类的LoadNativeLibrary()加载so文件,detail用于存储加载过程中的Log信息
    74    bool success = vm->LoadNativeLibrary(filename.c_str(), classLoader, &detail);
    75    if (success) {
    76      return nullptr;
    77    }
    78  }
    79
    80  // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
    81  env->ExceptionClear();
    82  return env->NewStringUTF(detail.c_str());
    83}
    Runtime_nativeLoad()

    根据代码加载so的分析,查看LoadNativeLibrary()源代码

    3225bool JavaVMExt::LoadNativeLibrary(const std::string& path,
    3226                                  Handle<mirror::ClassLoader> class_loader,
    3227                                  std::string* detail) {
    3228  detail->clear();
    3229
    3230  // 是否加载过该so文件,如果是就不需要再次加载
    3234  SharedLibrary* library;
    3235  Thread* self = Thread::Current();
    3236  {
    3237    // TODO: move the locking (and more of this logic) into Libraries.
    3238    MutexLock mu(self, libraries_lock);
    3239    library = libraries->Get(path);
    3240  }
    3241  if (library != nullptr) {
    3242    if (library->GetClassLoader() != class_loader.Get()) {
    3243      // The library will be associated with class_loader. The JNI
    3244      // spec says we can't load the same library into more than one
    3245      // class loader.
    3246      StringAppendF(detail, "Shared library "%s" already opened by "
    3247          "ClassLoader %p; can't open in ClassLoader %p",
    3248          path.c_str(), library->GetClassLoader(), class_loader.Get());
    3249      LOG(WARNING) << detail;
    3250      return false;
    3251    }
    3252    VLOG(jni) << "[Shared library "" << path << "" already loaded in "
    3253              << "ClassLoader " << class_loader.Get() << "]";
    3254    if (!library->CheckOnLoadResult()) {
    3255      StringAppendF(detail, "JNI_OnLoad failed on a previous attempt "
    3256          "to load "%s"", path.c_str());
    3257      return false;
    3258    }
    3259    return true;
    3260  }
    
    
    3274  // 没有加载过该so,需要加载
    3275  self->TransitionFromRunnableToSuspended(kWaitingForJniOnLoad);
    3276  const char* path_str = path.empty() ? nullptr : path.c_str();
          // 调用dlopen()加载so文件
    3277  void* handle = dlopen(path_str, RTLD_LAZY);
    3278  bool needs_native_bridge = false;
    3279  if (handle == nullptr) {
    3280    if (android::NativeBridgeIsSupported(path_str)) {
    3281      handle = android::NativeBridgeLoadLibrary(path_str, RTLD_LAZY);
    3282      needs_native_bridge = true;
    3283    }
    3284  }
    3285  self->TransitionFromSuspendedToRunnable();
    3286
    3287  VLOG(jni) << "[Call to dlopen("" << path << "", RTLD_LAZY) returned " << handle << "]";
    3288
    3289  if (handle == nullptr) {
    3290    *detail = dlerror();
    3291    LOG(ERROR) << "dlopen("" << path << "", RTLD_LAZY) failed: " << *detail;
    3292    return false;
    3293  }
    3294
    3295  // Create a new entry.
    3296  // TODO: move the locking (and more of this logic) into Libraries.
    3297  bool created_library = false;
    3298  {
    3299    MutexLock mu(self, libraries_lock);
    3300    library = libraries->Get(path);
    3301    if (library == nullptr) {  // 加载完后,新建SharedLibrary对象,并将path存入libraries
    3302      library = new SharedLibrary(path, handle, class_loader.Get());
    3303      libraries->Put(path, library);
    3304      created_library = true;
    3305    }
    3306  }
    3307  if (!created_library) {
    3308    LOG(INFO) << "WOW: we lost a race to add shared library: "
    3309        << """ << path << "" ClassLoader=" << class_loader.Get();
    3310    return library->CheckOnLoadResult();
    3311  }
    3312
    3313  VLOG(jni) << "[Added shared library "" << path << "" for ClassLoader " << class_loader.Get()
    3314      << "]";
    3315
    3316  bool was_successful = false;
    3317  void* sym = nullptr;
    3318  if (UNLIKELY(needs_native_bridge)) {
    3319    library->SetNeedsNativeBridge();
    3320    sym = library->FindSymbolWithNativeBridge("JNI_OnLoad", nullptr);
    3321  } else {
    3322    sym = dlsym(handle, "JNI_OnLoad");// 找到JNI_OnLoad()
    3323  }
    3324
    3325  if (sym == nullptr) {
    3326    VLOG(jni) << "[No JNI_OnLoad found in "" << path << ""]";
    3327    was_successful = true;
    3328  } else {
    3329    // Call JNI_OnLoad.  We have to override the current class
    3330    // loader, which will always be "null" since the stuff at the
    3331    // top of the stack is around Runtime.loadLibrary().  (See
    3332    // the comments in the JNI FindClass function.)
    3333    typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
    3334    JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
    3335    StackHandleScope<1> hs(self);
    3336    Handle<mirror::ClassLoader> old_class_loader(hs.NewHandle(self->GetClassLoaderOverride()));
    3337    self->SetClassLoaderOverride(class_loader.Get());
    3338
    3339    int version = 0;
    3340    {
    3341      ScopedThreadStateChange tsc(self, kNative);
    3342      VLOG(jni) << "[Calling JNI_OnLoad in "" << path << ""]";
              // 调用JNI_Onload()
    3343      version = (*jni_on_load)(this, nullptr);
    3344    }
    3345
    3346    if (runtime->GetTargetSdkVersion() != 0 && runtime->GetTargetSdkVersion() <= 21) {
    3347      fault_manager.EnsureArtActionInFrontOfSignalChain();
    3348    }
    3349    self->SetClassLoaderOverride(old_class_loader.Get());
    3350
    3351    if (version == JNI_ERR) {
    3352      StringAppendF(detail, "JNI_ERR returned from JNI_OnLoad in "%s"", path.c_str());
    3353    } else if (IsBadJniVersion(version)) {
    3354      StringAppendF(detail, "Bad JNI version returned from JNI_OnLoad in "%s": %d",
    3355                    path.c_str(), version);
    3356      // It's unwise to call dlclose() here, but we can mark it
    3357      // as bad and ensure that future load attempts will fail.
    3358      // We don't know how far JNI_OnLoad got, so there could
    3359      // be some partially-initialized stuff accessible through
    3360      // newly-registered native method calls.  We could try to
    3361      // unregister them, but that doesn't seem worthwhile.
    3362    } else {
    3363      was_successful = true;
    3364    }
    3365    VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure")
    3366              << " from JNI_OnLoad in "" << path << ""]";
    3367  }
    3368
    3369  library->SetResult(was_successful);
    3370  return was_successful;
    3371}
    LoadNativeLibrary()

    LoadNativeLibrary()函数执行过程:

      1. 判断so文件是否已经加载,若已经加载判断与class_Loader是否重复

      2. 如果so文件没有被加载,dlopen()打开so文件加载

      3. 调用dlsym() 加载 “JNI_OnLoad”函数地址

      4. 调用JNI_OnLoad()函数

      至此Native层so文件加载完成,根据分析结果追踪dlopen()

          dlopen()源码: /bionic/linker/dlfcn.cpp

    82void* dlopen(const char* filename, int flags) {
    83  return dlopen_ext(filename, flags, nullptr);
    84}

    跟踪dlopen_ext()

    68static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
    69  ScopedPthreadMutexLocker locker(&g_dl_mutex);
    70  soinfo* result = do_dlopen(filename, flags, extinfo);
    71  if (result == nullptr) {
    72    __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
    73    return nullptr;
    74  }
    75  return result;
    76}
    dlopen_ext()

    根据代码filename指向的 .so文件,返回值为soinfo*,指向so文件指针,所以dlopen_ext()返回的指针指向 soinfo对象

    跟踪 do_dlopen():/bionic/linker/linker.cpp

    1041soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
    
    1042  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) {
    1043    DL_ERR("invalid flags to dlopen: %x", flags);
    1044    return nullptr;
    1045  }
    1046  if (extinfo != nullptr) {
    1047    if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
    1048      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
    1049      return nullptr;
    1050    }
    1051    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
    1052        (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
    1053      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
    1054      return nullptr;
    1055    }
    1056  }
           // extinfo为null
    
    1057  protect_data(PROT_READ | PROT_WRITE);
    1058  soinfo* si = find_library(name, flags, extinfo);
    1059  if (si != nullptr) {
            // 初始化
    1060    si->CallConstructors();
    1061  }
    1062  protect_data(PROT_READ);
    1063  return si;
    1064}
    do_dlopen()

    find_library()得到soinfo对象,分析源码需要跟踪find_library()和CallConstructors(),根据代码顺序继续分析

      do_dlopen()总共两部分

      do_dlopen()的第一部分:

        find_library():

    968static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) {
    
    969  if (name == nullptr) {
    970    somain->ref_count++;
    971    return somain;
    972  }
    973
    974  soinfo* si;
    975
    976  if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) {
    977    return nullptr;
    978  }
    979
    980  return si;
    981}
    find_library()

    根据代码跟踪 find_libraries()的参数:/bionic/linker/linker.cpp

        find_libraries()参数:

        const char* const library_names[], //so文件名的数组

        size_t library_names_size, //

        soinfo* soinfos[], //指向soinfos数组的指针,将library_names中so的结果存入soinfos数组中

        soinfo* ld_preloads[], //ld_preloads = NULL

        size_t ld_preloads_size, //ld_preloads_size = 0

        int dlflags,

        const android_dlextinfo* extinfo //extinfo = NULL

    896static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[],
    897    soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) {
    898    // Step 1: prepare.
                   // a.宽度优先搜索的栈,父节点的依赖库为其子节点,根节点是代加载的.so文件    
    899  LoadTaskList load_tasks;
                   // b.初始化
    900  for (size_t i = 0; i < library_names_size; ++i) {
    901    const char* name = library_names[i];
    902    load_tasks.push_back(LoadTask::create(name, nullptr));
    903  }
    904
    905  
                    // c.该so文件和其它所有依赖库的列表
    907  SoinfoLinkedList found_libs;
    908  size_t soinfos_size = 0;
    909
    910  auto failure_guard = make_scope_guard([&]() {
    911    // Housekeeping
    912    load_tasks.for_each([] (LoadTask* t) {
    913      LoadTask::deleter(t);
    914    });
    915
    916    for (size_t i = 0; i<soinfos_size; ++i) {
    917      soinfo_unload(soinfos[i]);
    918    }
    919  });
    920
    921  // Step 2: 
            //  优先搜索加载该.so文件和其依赖库
    
    922  for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) {
                   // 加载so文件
    923    soinfo* si = find_library_internal(load_tasks, task->get_name(), dlflags, extinfo);// extinfo == null
    924    if (si == nullptr) {
    925      return false;
    926    }
    927     // needed_by依赖于si
    928    soinfo* needed_by = task->get_needed_by();
    929
    930    if (is_recursive(si, needed_by)) {
            // 判断是否有递归依赖关系
    931      return false;
    932    }
    933     // si引用计数
    934    si->ref_count++;        
    935    if (needed_by != nullptr) {
    936      needed_by->add_child(si);
    937    }
    938    found_libs.push_front(si);
    939
    940    // When ld_preloads is not null first
    941    // ld_preloads_size libs are in fact ld_preloads.
    942    if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) {
    943      ld_preloads[soinfos_size] = si;
    944    }
    945
    946    if (soinfos_size<library_names_size) {
            // 只将library_names中对应的soinfos存入soinfos
    947      soinfos[soinfos_size++] = si;
    948    }
    949  }
    950
    951     // Step 3: 
            // 链接加载库
    952  soinfo* si;
    953  while ((si = found_libs.pop_front()) != nullptr) {
    954    if ((si->flags & FLAG_LINKED) == 0) {
              // 如果si没有链接,对si进行链接
    955      if (!si->LinkImage(extinfo)) {
               // extinfo == null
    956        return false;
    957      }
    958      si->flags |= FLAG_LINKED;
    959    }
    960  }
    961
    962  // All is well - found_libs and load_tasks are empty at this point
    963  // and all libs are successfully linked.
    964  failure_guard.disable();
    965  return true;
    966}
    find_libraries()

    find_libraries()对library_names[ ]中的so文件加载到内存,进行链接

      find_libraries()分三步骤:

        第一步:初始化:

          a) 加载的so可能以来其他库,采用优先搜索依次加载方式。搜索树中父节点的依赖库为其子节点。根节点是so文件

          b) 初始化

          c) found_libs是so文件和其依赖库的列表

        第二步:宽度优先搜索加载so:

          d) find_library_internal()将so载入内存

        第三步:对加载的so进行链接:

          根据上述分析,查看

          find_library_internal()函数源码,用于加载so /bionic/linker/linker.cpp

    865static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) {// extinfo==null
    866   // 检查是否被加载过
    867  soinfo* si = find_loaded_library_by_name(name);
    868
    869  // 加载过直接返回si,否则调用load_library
    871  if (si == nullptr) {
    872    TRACE("[ '%s' has not been found by name.  Trying harder...]", name);
    873    si = load_library(load_tasks, name, dlflags, extinfo);
    874  }
    875
    876  return si;
    877}
    find_library_internal()

    跟进查看load_library()源码:

    777static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) {// extinfo == null
    
    778  int fd = -1; // so文件描述符
    779  off64_t file_offset = 0;
    780  ScopedFd file_guard(-1);
    781   // 第一部分:
    782  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
    783    fd = extinfo->library_fd;
    784    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
    785      file_offset = extinfo->library_fd_offset;
    786    }
    787  } else {
    788    // 打开so文件
    789    fd = open_library(name);
    790    if (fd == -1) {
    791      DL_ERR("library "%s" not found", name);
    792      return nullptr;
    793    }
    794
    795    file_guard.reset(fd);
    796  }
    797     // 文件偏移必须是PAGE_SIZE的整数倍,这里file_offset == 0
    798  if ((file_offset % PAGE_SIZE) != 0) {
    799    DL_ERR("file offset for the library "%s" is not page-aligned: %" PRId64, name, file_offset);
    800    return nullptr;
    801  }
    802
    803  struct stat file_stat;
    804  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
            // 获取so文件的状态
    805    DL_ERR("unable to stat file for the library "%s": %s", name, strerror(errno));
    806    return nullptr;
    807  }
    808
    809  // 因为Linux下可以生成文件的链接文件,这里检查so文件是否以不同名字加载
    811  for (soinfo* si = solist; si != nullptr; si = si->next) {
    812    if (si->get_st_dev() != 0 &&
    813        si->get_st_ino() != 0 &&
    814        si->get_st_dev() == file_stat.st_dev &&
    815        si->get_st_ino() == file_stat.st_ino &&
    816        si->get_file_offset() == file_offset) {
    817      TRACE("library "%s" is already loaded under different name/path "%s" - will return existing soinfo", name, si->name);
    818      return si;
    819    }
    820  }
    821
    822  if ((dlflags & RTLD_NOLOAD) != 0) {
    823    DL_ERR("library "%s" wasn't loaded and RTLD_NOLOAD prevented it", name);
    824    return nullptr;
    825  }
    826   // 第二部分:
    827  // 读取ELF头,加载段     file_offset == 0
    828  ElfReader elf_reader(name, fd, file_offset);
    829  if (!elf_reader.Load(extinfo)) {
    830    return nullptr;
    831  }
    832   // 第三部分
          //  为soinfo分配空间
    833  soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset);
    834  if (si == nullptr) {
    835    return nullptr;
    836  }
            // 加载 so 文件时,mmap 得到的空间的首地址
    837  si->base = elf_reader.load_start();
            // ReserveAddressSpace 中开辟的内存空间的大小
    838  si->size = elf_reader.load_size();
            // 加载段时的基址,load_bias+p_vaddr 为段的实际内存地址
    839  si->load_bias = elf_reader.load_bias();
            // program header 的个数
    840  si->phnum = elf_reader.phdr_count();
            // program header table 在内存中的起始地址
    841  si->phdr = elf_reader.loaded_phdr();
    842
    843  if (!si->PrelinkImage()) {
            // 解析.dynmaic section
    844    soinfo_free(si);
    845    return nullptr;
    846  }
    847     // 将该so文件依赖的库添加到待加载队列中
    848  for_each_dt_needed(si, [&] (const char* name) {
            // si依赖于name的库
    849    load_tasks.push_back(LoadTask::create(name, si));
    850  });
    851
    852  return si;
    853}
    854
    855static soinfo *find_loaded_library_by_name(const char* name) {
    856  const char* search_name = SEARCH_NAME(name);
    857  for (soinfo* si = solist; si != nullptr; si = si->next) {
    858    if (!strcmp(search_name, si->name)) {
    859      return si;
    860    }
    861  }
    862  return nullptr;
    863}
    load_library()
            load_library()分三个部分:

            第一部分:打开.so文件,并判断是否已经加载

                  内存页的大小:PAGE_SIZE为4096

            第二部分:加载.so文件的可加载段

                  用ElfReader类解析ELF头

    根据源码Load()的源码:

    135bool ElfReader::Load(const android_dlextinfo* extinfo) {
                 // ReadElfHeader()读取ELF头结果给ElfReader的Elf32_Ehdr header_,成员变量
    136  return ReadElfHeader() &&
    137         VerifyElfHeader() &&
    138         ReadProgramHeader() &&
    139         ReserveAddressSpace(extinfo) &&
    140         LoadSegments() &&
    141         FindPhdr();
    142}
    Load()

    根据ElfReader源码,分析return的返回值的函数源码

     VerifyElfHeader():检查ELF头某些字段是否合法,根据源码,ELF头中,byte_ident[16]字段的后10位没有进行校验

    159bool ElfReader::VerifyElfHeader() {
    
            // 检查magicNum 与 177ELF
    160  if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
    161    DL_ERR(""%s" has bad ELF magic", name_);
    162    return false;
    163  }
    164
    165  // 检测ELF为数与目前操作系统的为数是否相同(32位或64位)
    167  int elf_class = header_.e_ident[EI_CLASS];
    168#if defined(__LP64__)
    169  if (elf_class != ELFCLASS64) {
    170    if (elf_class == ELFCLASS32) {
    171      DL_ERR(""%s" is 32-bit instead of 64-bit", name_);
    172    } else {
    173      DL_ERR(""%s" has unknown ELF class: %d", name_, elf_class);
    174    }
    175    return false;
    176  }
    177#else
    178  if (elf_class != ELFCLASS32) {
    179    if (elf_class == ELFCLASS64) {
    180      DL_ERR(""%s" is 64-bit instead of 32-bit", name_);
    181    } else {
    182      DL_ERR(""%s" has unknown ELF class: %d", name_, elf_class);
    183    }
    184    return false;
    185  }
    186#endif
    187   // 该so文件必须是小端存储
    188  if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
            // EI_DATA=5,ELFDATA2LSB=1
    189    DL_ERR(""%s" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
    190    return false;
    191  }
    192   // 该so文件必须共享目标文件
    193  if (header_.e_type != ET_DYN) {
            // ET_DYN=3
    194    DL_ERR(""%s" has unexpected e_type: %d", name_, header_.e_type);
    195    return false;
    196  }
    197   // 版本号必须为1
    198  if (header_.e_version != EV_CURRENT) {
    199    DL_ERR(""%s" has unexpected e_version: %d", name_, header_.e_version);
    200    return false;
    201  }
    202   // 如果目标平台是arm,ELF_TARG_MACH=40
    203  if (header_.e_machine != ELF_TARG_MACH) {
    204    DL_ERR(""%s" has unexpected e_machine: %d", name_, header_.e_machine);
    205    return false;
    206  }
    207
    208  return true;
    209}
    VerifyElfHeader()

     ReadProgramHeader()将 program header table从.so 文件通过 mmap64 映射到只读私有匿名内存

    213bool ElfReader::ReadProgramHeader() {
    214  phdr_num_ = header_.e_phnum;// phdr的数目
    215
    216  // Like the kernel, we only accept program header tables that
    217  // are smaller than 64KiB.
    218  if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
    219    DL_ERR(""%s" has invalid e_phnum: %zd", name_, phdr_num_);
    220    return false;
    221  }
    222
    223  ElfW(Addr) page_min = PAGE_START(header_.e_phoff);// 0
    224  ElfW(Addr) page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(ElfW(Phdr))));
          // pht在页中的偏移
    225  ElfW(Addr) page_offset = PAGE_OFFSET(header_.e_phoff);
    226   // pht需要的映射内存大小
    227  phdr_size_ = page_max - page_min;
    228
    229  void* mmap_result = mmap64(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, file_offset_ + page_min);
    230  if (mmap_result == MAP_FAILED) {
    231    DL_ERR(""%s" phdr mmap failed: %s", name_, strerror(errno));
    232    return false;
    233  }
    234
    235  phdr_mmap_ = mmap_result;
    236  phdr_table_ = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(mmap_result) + page_offset);
    237  return true;
    238}
    ReadProgramHeader()

     ReserveAddressSpace()通过 mmap 创建足够大的匿名内存空间, 以便能够容纳所有可以加载的段

    292bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
    
    293  ElfW(Addr) min_vaddr;
          // 加载所有段所需要的内存空间
    294  load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
    295  if (load_size_ == 0) {
    296    DL_ERR(""%s" has no loadable segments", name_);
    297    return false;
    298  }
    299
    300  uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
    301  void* start;
    302  size_t reserved_size = 0;
    303  bool reserved_hint = true;
    304
    305  if (extinfo != nullptr) {
    306    if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
    307      reserved_size = extinfo->reserved_size;
    308      reserved_hint = false;
    309    } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
    310      reserved_size = extinfo->reserved_size;
    311    }
    312  }
    313
    314  if (load_size_ > reserved_size) {
    315    if (!reserved_hint) {
    316      DL_ERR("reserved address space %zd smaller than %zd bytes needed for "%s"",
    317             reserved_size - load_size_, load_size_, name_);
    318      return false;
    319    }
    320    int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
            // 分配空间
    321    start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
    322    if (start == MAP_FAILED) {
    323      DL_ERR("couldn't reserve %zd bytes of address space for "%s"", load_size_, name_);
    324      return false;
    325    }
    326  } else {
    327    start = extinfo->reserved_addr;
    328  }
    329   // 分配匿名内存空间首地址
    330  load_start_ = start;
    331  load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
    332  return true;
    333}
    ReserveAddressSpace()

     LoadSegments()函数

    335bool ElfReader::LoadSegments() {
    
    336  for (size_t i = 0; i < phdr_num_; ++i) {
    337    const ElfW(Phdr)* phdr = &phdr_table_[i];
    338     // 遍历 program header table 找到可加载段
    339    if (phdr->p_type != PT_LOAD) {
    340      continue;
    341    }
    342
    343    // Segment addresses in memory.
            // 段在内存中的起始地址
    344    ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
            // 段在内存中的结束地址
    345    ElfW(Addr) seg_end   = seg_start + phdr->p_memsz;
    346     // seg_start 所在页的起始地址
    347    ElfW(Addr) seg_page_start = PAGE_START(seg_start);
            // seg_end 所在页的下一页的起始地址
    348    ElfW(Addr) seg_page_end   = PAGE_END(seg_end);
    349     // 文件中段的结束位置在内存中的地址
    350    ElfW(Addr) seg_file_end   = seg_start + phdr->p_filesz;
    351
    352    // File offsets.
            // 段在文件中的偏移首地址
    353    ElfW(Addr) file_start = phdr->p_offset;
            // 段在文件中的结束地址
    354    ElfW(Addr) file_end   = file_start + phdr->p_filesz;
    355     // file_start 所在页的起始地址
    356    ElfW(Addr) file_page_start = PAGE_START(file_start);
            // 需要映射的文件长度,file_length>=phdr->p_filesz
    357    ElfW(Addr) file_length = file_end - file_page_start;
    358
    359    if (file_length != 0) {
            // 将文件中的段映射到内存
    360      void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
    361                            file_length,
    362                            PFLAGS_TO_PROT(phdr->p_flags),
    363                            MAP_FIXED|MAP_PRIVATE,
    364                            fd_,
    365                            file_offset_ + file_page_start);
    366      if (seg_addr == MAP_FAILED) {
    367        DL_ERR("couldn't map "%s" segment %zd: %s", name_, i, strerror(errno));
    368        return false;
    369      }
    370    }
    371
    372    // 将最后一页中,不是段内容的数据置 0 
    374    if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
    375      memset(reinterpret_cast<void*>(seg_file_end), 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
    376    }
    377
    378    seg_file_end = PAGE_END(seg_file_end);
    379
    380    // seg_file_end is now the first page address after the file
    381    // content. If seg_end is larger, we need to zero anything
    382    // between them. This is done by using a private anonymous
    383    // map for all extra pages.
    384    if (seg_page_end > seg_file_end) {
    385      void* zeromap = mmap(reinterpret_cast<void*>(seg_file_end),
    386                           seg_page_end - seg_file_end,
    387                           PFLAGS_TO_PROT(phdr->p_flags),
    388                           MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
    389                           -1,
    390                           0);
             // 额外的内容置 0
    391      if (zeromap == MAP_FAILED) {
    392        DL_ERR("couldn't zero fill "%s" gap: %s", name_, strerror(errno));
    393        return false;
    394      }
    395    }
    396  }
    397  return true;
    398}
    399
    LoadSegments()

    加载完.so 文件后,Load()继续调用 FindPhdr()函数检查可加载段中是否包含 program header table。

    728bool ElfReader::FindPhdr() {
    729  const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
    730
    731  // 首先检查是否有类型是 PT_PHDR 的段,即 program header table
    732  for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
            // load_bias_ + phdr->p_vaddr 是 phdr 在内存中的起始地址
    733    if (phdr->p_type == PT_PHDR) {
              // 检查是否在内存中  
    734      return CheckPhdr(load_bias_ + phdr->p_vaddr);
    735    }
    736  }
    737
    738  // 检查第一个可加载段。如果它在文件中的偏移是 0,那么该段以 ELF 头
    739  // 开始,通过 ELF 头能计算 program header table 的地址
    741  for (const ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
    742    if (phdr->p_type == PT_LOAD) {
    743      if (phdr->p_offset == 0) {
    744        ElfW(Addr)  elf_addr = load_bias_ + phdr->p_vaddr;
    745        const ElfW(Ehdr)* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(elf_addr);
               // ehdr->e_phoff 是 pht 在文件中的偏移
    746        ElfW(Addr)  offset = ehdr->e_phoff;
               // 检查是否在内存中
    747        return CheckPhdr((ElfW(Addr))ehdr + offset);
    748      }
    749      break;
    750    }
    751  }
    752
    753  DL_ERR("can't find loaded phdr for "%s"", name_);
    754  return false;
    755}
                   FindPhdr()两种方式确定program header table是否在内存,调用CheckPhdr()实现
    760bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
    761  const ElfW(Phdr)* phdr_limit = phdr_table_ + phdr_num_;
        // loaded_end 是 pht 在内存中的结束地址
    762  ElfW(Addr) loaded_end = loaded + (phdr_num_ * sizeof(ElfW(Phdr)));
    763  for (ElfW(Phdr)* phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
    764    if (phdr->p_type != PT_LOAD) {
    765      continue;
    766    }
    767    ElfW(Addr) seg_start = phdr->p_vaddr + load_bias_;
    768    ElfW(Addr) seg_end = phdr->p_filesz + seg_start;
    769    if (seg_start <= loaded && loaded_end <= seg_end) {
            // 遍历每一个可加载段,检查 pht 的地址范围是否在可加载段中
    770      loaded_phdr_ = reinterpret_cast<const ElfW(Phdr)*>(loaded);
    771      return true;
    772    }
    773  }
    774  DL_ERR(""%s" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
    775  return false;
    776}
    FindPhdr()
            ElfReader.Load()加载so的过程:
               1. ReadElfHeader():从.so 文件中读取 ELF 头;
               2.  VerifyElfHeader():校验 ELF 头;
               3.  ReadProgramHeader():将.so 文件的 program header table 映射到内存;
               4.  ReserveAddressSpace():开辟匿名内存空间;
               5.  LoadSegments():将可加载段加载到 ReserveAddressSpace 开辟的空间中;
               6.  FindPhdr():校验 program header table 是否在内存中。
     

            第三部分:创建soinfo对象,解析.dynmaic section,并将该.so文件的依赖库添加到待加载的队列中。

                                           Load_library()中PrelinkImage()解析so文件的dynamic setction

                                             dynamic section的定义

    1631// Dynamic table entry for ELF64.
    1632struct Elf64_Dyn
    1633{
    1634  Elf64_Sxword d_tag;           // Type of dynamic table entry.
    1635  union
    1636  {
    1637      Elf64_Xword d_val;        // Integer value of entry.
    1638      Elf64_Addr  d_ptr;        // Pointer value of entry.
    1639  } d_un;
    1640};
     dynamic section

                                       PrelinkImage()解析的源码

    1858bool soinfo::PrelinkImage() {
    1859  /* Extract dynamic section */
    1860  ElfW(Word) dynamic_flags = 0;
          // 根据 program header table 找到.dynamic section
    1861  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
    1862
    1863  /* We can't log anything until the linker is relocated */
    1864  bool relocating_linker = (flags & FLAG_LINKER) != 0;
    1865  if (!relocating_linker) {
    1866    INFO("[ linking %s ]", name);
    1867    DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags);
    1868  }
    1869
    1870  if (dynamic == nullptr) {
    1871    if (!relocating_linker) {
    1872      DL_ERR("missing PT_DYNAMIC in "%s"", name);
    1873    }
    1874    return false;
    1875  } else {
    1876    if (!relocating_linker) {
    1877      DEBUG("dynamic = %p", dynamic);
    1878    }
    1879  }
    1880    // 找到.ARM.exidx sectioin 在内存中的地址
    1881#if defined(__arm__)
    1882  (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
    1883                                  &ARM_exidx, &ARM_exidx_count);
    1884#endif
    1885
    1886  // 该so依赖库的个数
    1887  uint32_t needed_count = 0;
            // 遍历.dynamic
    1888  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
    1889    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
    1890          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
    1891    switch (d->d_tag) {
    1892      case DT_SONAME:
    1893        // TODO: glibc dynamic linker uses this name for
    1894        // initial library lookup; consider doing the same here.
    1895        break;
    1896       // hash 表相关信息
    1897      case DT_HASH:  
    1898        nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
    1899        nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
    1900        bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
    1901        chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4);
    1902        break;
    1903      // 字符串表的偏移,与.dynstr section 对应,d_un.d_ptr 与 s_addr 相等
    1904      case DT_STRTAB:  
    1905        strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
    1906        break;
    1907      // 字符串表的大小(字节)
    1908      case DT_STRSZ:
    1909        strtab_size = d->d_un.d_val;
    1910        break;
    1911      // 符号表的偏移
    1912      case DT_SYMTAB:
    1913        symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
    1914        break;
    1915     // 符号表项的大小(字节)
    1916      case DT_SYMENT:
    1917        if (d->d_un.d_val != sizeof(ElfW(Sym))) {
    1918          DL_ERR("invalid DT_SYMENT: %zd", static_cast<size_t>(d->d_un.d_val));
    1919          return false;
    1920        }
    1921        break;
    1922
    1923      case DT_PLTREL:
    1924#if defined(USE_RELA)
    1925        if (d->d_un.d_val != DT_RELA) {
    1926          DL_ERR("unsupported DT_PLTREL in "%s"; expected DT_RELA", name);
    1927          return false;
    1928        }
    1929#else
    1930        if (d->d_un.d_val != DT_REL) {
    1931          DL_ERR("unsupported DT_PLTREL in "%s"; expected DT_REL", name);
    1932          return false;
    1933        }
    1934#endif
    1935        break;
    1936      // 与过程链接表相关的重定位表的偏移,与.rel.plt section 对应
    1937      case DT_JMPREL:
    1938#if defined(USE_RELA)
    1939        plt_rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
    1940#else
    1941        plt_rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
    1942#endif
    1943        break;
    1944
    1945      case DT_PLTRELSZ:
    1946#if defined(USE_RELA)
    1947        plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
    1948#else
    1949        plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
    1950#endif
    1951        break;
    1952      // 与过程链接表相关的重定位表的大小(字节)
    1953      case DT_PLTGOT:
    1954#if defined(__mips__)
    1955        // Used by mips and mips64.
    1956        plt_got = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
    1957#endif
    1958        // Ignore for other platforms... (because RTLD_LAZY is not supported)
    1959        break;
    1960
    1961      case DT_DEBUG:
    1962        // Set the DT_DEBUG entry to the address of _r_debug for GDB
    1963        // if the dynamic table is writable
    1964// FIXME: not working currently for N64
    1965// The flags for the LOAD and DYNAMIC program headers do not agree.
    1966// The LOAD section containing the dynamic table has been mapped as
    1967// read-only, but the DYNAMIC header claims it is writable.
    1968#if !(defined(__mips__) && defined(__LP64__))
    1969        if ((dynamic_flags & PF_W) != 0) {
    1970          d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
    1971        }
    1972        break;
    1973#endif
    1974#if defined(USE_RELA)
    1975      case DT_RELA:
    1976        rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
    1977        break;
    1978
    1979      case DT_RELASZ:
    1980        rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
    1981        break;
    1982
    1983      case DT_RELAENT:
    1984        if (d->d_un.d_val != sizeof(ElfW(Rela))) {
    1985          DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
    1986          return false;
    1987        }
    1988        break;
    1989
    1990      // ignored (see DT_RELCOUNT comments for details)
    1991      case DT_RELACOUNT:
    1992        break;
    1993      
    1994      case DT_REL:
    1995        DL_ERR("unsupported DT_REL in "%s"", name);
    1996        return false;
    1997
    1998      case DT_RELSZ:
    1999        DL_ERR("unsupported DT_RELSZ in "%s"", name);
    2000        return false;
    2001#else
            // 重定位表的偏移,与.rel.dyn section 对应
    2002      case DT_REL:
    2003        rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
    2004        break;
    2005      // 重定位表的总大小(字节)
    2006      case DT_RELSZ:
    2007        rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
    2008        break;
    2009      // 重定位表项的大小(字节)
    2010      case DT_RELENT:
    2011        if (d->d_un.d_val != sizeof(ElfW(Rel))) {
    2012          DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
    2013          return false;
    2014        }
    2015        break;
    2016
    2017      // "Indicates that all RELATIVE relocations have been concatenated together,
    2018      // and specifies the RELATIVE relocation count."
    2019      //
    2020      // TODO: Spec also mentions that this can be used to optimize relocation process;
    2021      // Not currently used by bionic linker - ignored.
    2022      case DT_RELCOUNT:
    2023        break;
    2024      case DT_RELA:
    2025        DL_ERR("unsupported DT_RELA in "%s"", name);
    2026        return false;
    2027#endif
             // 初始化函数 init 的偏移
    2028      case DT_INIT:
    2029        init_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
    2030        DEBUG("%s constructors (DT_INIT) found at %p", name, init_func);
    2031        break;
    2032      // 结束函数的偏移    
    2033      case DT_FINI:
    2034        fini_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
    2035        DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func);
    2036        break;
    2037      // 初始化函数数组 init_array 的偏移
    2038      case DT_INIT_ARRAY:
    2039        init_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
    2040        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array);
    2041        break;
    2042      // init_array 的大小(字节)
    2043      case DT_INIT_ARRAYSZ:
    2044        init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
    2045        break;
    2046
    2047      case DT_FINI_ARRAY:
    2048        fini_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
    2049        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array);
    2050        break;
    2051
    2052      case DT_FINI_ARRAYSZ:
    2053        fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
    2054        break;
    2055
    2056      case DT_PREINIT_ARRAY:
    2057        preinit_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
    2058        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array);
    2059        break;
    2060
    2061      case DT_PREINIT_ARRAYSZ:
    2062        preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
    2063        break;
    2064
    2065      case DT_TEXTREL:
    2066#if defined(__LP64__)
    2067        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file "%s"", name);
    2068        return false;
    2069#else
    2070        has_text_relocations = true;
    2071        break;
    2072#endif
    2073
    2074      case DT_SYMBOLIC:
    2075        has_DT_SYMBOLIC = true;
    2076        break;
    2077      // d->d_un.d_val 是依赖库名字在字符串表中的索引
    2078      case DT_NEEDED:
    2079        ++needed_count;
    2080        break;
    2081
    2082      case DT_FLAGS:
    2083        if (d->d_un.d_val & DF_TEXTREL) {
    2084#if defined(__LP64__)
    2085          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file "%s"", name);
    2086          return false;
    2087#else
    2088          has_text_relocations = true;
    2089#endif
    2090        }
    2091        if (d->d_un.d_val & DF_SYMBOLIC) {
    2092          has_DT_SYMBOLIC = true;
    2093        }
    2094        break;
    2095
    2096      case DT_FLAGS_1:
    2097        if ((d->d_un.d_val & DF_1_GLOBAL) != 0) {
    2098          rtld_flags |= RTLD_GLOBAL;
    2099        }
    2100        // TODO: Implement other flags
    2101
    2102        if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) {
    2103          DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val));
    2104        }
    2105        break;
    2106#if defined(__mips__)
    2107      case DT_MIPS_RLD_MAP:
    2108        // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
    2109        {
    2110          r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
    2111          *dp = &_r_debug;
    2112        }
    2113        break;
    2114
    2115      case DT_MIPS_RLD_VERSION:
    2116      case DT_MIPS_FLAGS:
    2117      case DT_MIPS_BASE_ADDRESS:
    2118      case DT_MIPS_UNREFEXTNO:
    2119        break;
    2120
    2121      case DT_MIPS_SYMTABNO:
    2122        mips_symtabno = d->d_un.d_val;
    2123        break;
    2124
    2125      case DT_MIPS_LOCAL_GOTNO:
    2126        mips_local_gotno = d->d_un.d_val;
    2127        break;
    2128
    2129      case DT_MIPS_GOTSYM:
    2130        mips_gotsym = d->d_un.d_val;
    2131        break;
    2132#endif
    2133      // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
    2134      case DT_BIND_NOW:
    2135        break;
    2136
    2137      // Ignore: bionic does not support symbol versioning...
    2138      case DT_VERSYM:
    2139      case DT_VERDEF:
    2140      case DT_VERDEFNUM:
    2141        break;
    2142
    2143      default:
    2144        if (!relocating_linker) {
    2145          DL_WARN("%s: unused DT entry: type %p arg %p", name,
    2146              reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
    2147        }
    2148        break;
    2149    }
    2150  }
    2151
    2152  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
    2153        reinterpret_cast<void*>(base), strtab, symtab);
    2154
    2155  // Sanity checks.
    2156  if (relocating_linker && needed_count != 0) {
    2157    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
    2158    return false;
    2159  }
    2160  if (nbucket == 0) {
    2161    DL_ERR("empty/missing DT_HASH in "%s" (built with --hash-style=gnu?)", name);
    2162    return false;
    2163  }
    2164  if (strtab == 0) {
    2165    DL_ERR("empty/missing DT_STRTAB in "%s"", name);
    2166    return false;
    2167  }
    2168  if (symtab == 0) {
    2169    DL_ERR("empty/missing DT_SYMTAB in "%s"", name);
    2170    return false;
    2171  }
    2172  return true;
    2173}
    PrelinkImage()

            至此, load_library()函数分析完了find_libraries()分析结束返回上一个函数find_libraries()函数

                   find_libraries()第三步:

          第三步:对加载的so进行链接:调用LinkImage()

           LinkImage()源码:

    2175bool soinfo::LinkImage(const android_dlextinfo* extinfo) {
    2176
    2177#if !defined(__LP64__)
    2178  if (has_text_relocations) {
    2179    // Make segments writable to allow text relocations to work properly. We will later call
    2180    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
    2181    DL_WARN("%s has text relocations. This is wasting memory and prevents "
    2182            "security hardening. Please fix.", name);
            // 使段可读写,通过系统调用 mprotect()来设置
    2183    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
    2184      DL_ERR("can't unprotect loadable segments for "%s": %s",
    2185             name, strerror(errno));
    2186      return false;
    2187    }
    2188  }
    2189#endif
    2190
    2191#if defined(USE_RELA)
    2192  if (rela != nullptr) {
    2193    DEBUG("[ relocating %s ]", name);
    2194    if (Relocate(rela, rela_count)) {
    2195      return false;
    2196    }
    2197  }
    2198  if (plt_rela != nullptr) {
    2199    DEBUG("[ relocating %s plt ]", name);
    2200    if (Relocate(plt_rela, plt_rela_count)) {
    2201      return false;
    2202    }
    2203  }
    2204#else
    2205  if (rel != nullptr) {
    2206    DEBUG("[ relocating %s ]", name);
            // 对重定位表中所指的符号进行重定位
    2207    if (Relocate(rel, rel_count)) {
    2208      return false;
    2209    }
    2210  }
            // 与调用导入函数相关
    2211  if (plt_rel != nullptr) {
    2212    DEBUG("[ relocating %s plt ]", name);
            // 对重定位表中所指的符号进行重定位
    2213    if (Relocate(plt_rel, plt_rel_count)) {
    2214      return false;
    2215    }
    2216  }
    2217#endif
    2218
    2219#if defined(__mips__)
    2220  if (!mips_relocate_got(this)) {
    2221    return false;
    2222  }
    2223#endif
    2224
    2225  DEBUG("[ finished linking %s ]", name);
    2226
    2227#if !defined(__LP64__)
    2228  if (has_text_relocations) {
    2229    // All relocations are done, we can protect our segments back to read-only.
    2230    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
    2231      DL_ERR("can't protect segments for "%s": %s",
    2232             name, strerror(errno));
    2233      return false;
    2234    }
    2235  }
    2236#endif
    2237
    2238  /* We can also turn on GNU RELRO protection */
    2239  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
    2240    DL_ERR("can't enable GNU RELRO protection for "%s": %s",
    2241           name, strerror(errno));
    2242    return false;
    2243  }
    2244
    2245  /* Handle serializing/sharing the RELRO segment */
    2246  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
    2247    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
    2248                                       extinfo->relro_fd) < 0) {
    2249      DL_ERR("failed serializing GNU RELRO section for "%s": %s",
    2250             name, strerror(errno));
    2251      return false;
    2252    }
    2253  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
    2254    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
    2255                                 extinfo->relro_fd) < 0) {
    2256      DL_ERR("failed mapping GNU RELRO section for "%s": %s",
    2257             name, strerror(errno));
    2258      return false;
    2259    }
    2260  }
    2261
    2262  notify_gdb_of_load(this);
    2263  return true;
    2264}
    LinkImage()

    对rel.dyn 和.rel.plt 两个重定位表都是调用Relocate()来进行重定位的。

    159#define ELF32_R_SYM(x) ((x) >> 8)
    
    160#define ELF32_R_TYPE(x) ((x) & 0xff)
    
    
    164typedef struct elf32_rel {
    165 Elf32_Addr r_offset;
    166 Elf32_Word r_info;
    167} Elf32_Rel;
    重定位的数据结构

                         Relocate()源码

    1359int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) {
            //遍历重定位表
    1360  for (size_t idx = 0; idx < count; ++idx, ++rel) {
            // 重定位类型
    1361    unsigned type = ELFW(R_TYPE)(rel->r_info);
    1362   // 符号表索引
            // 重定位的地址,即 reloc 处的值需要重新计算,对于导入函数来说,地址 reloc 在 got 表中,reloc 处应该是函数的实际地址,代码中函数的地址其实是其在 got 表中的偏移,再从 got 表中跳转到函数的实际地址。
    1363    unsigned sym = ELFW(R_SYM)(rel->r_info);
    1364    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
            // 符号的地址
    1365    ElfW(Addr) sym_addr = 0;
            // 符号的名称
    1366    const char* sym_name = nullptr;
    1367
    1368    DEBUG("Processing '%s' relocation at index %zd", name, idx);
    1369    if (type == 0) { // R_*_NONE
    1370      continue;
    1371    }
    1372    // 该符号在其定义 so 中的记录
    1373    ElfW(Sym)* s = nullptr;
            // 定义该符号的 so
    1374    soinfo* lsi = nullptr;
    1375
    1376    if (sym != 0) {
             // 得到符号的名称
    1377      sym_name = get_string(symtab[sym].st_name);
            // 查找 sym_name 定义在哪个 so
    1378      s = soinfo_do_lookup(this, sym_name, &lsi);
    1379      if (s == nullptr) {
               // 如果该符号没有定义,那么它的绑定类型必须是弱引用
    1380        // We only allow an undefined symbol if this is a weak reference...
    1381        s = &symtab[sym];
    1382        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
    1383          DL_ERR("cannot locate symbol "%s" referenced by "%s"...", sym_name, name);
    1384          return -1;
    1385        }
    1386
    1387        /* IHI0044C AAELF 4.5.1.1:
    1388
    1389           Libraries are not searched to resolve weak references.
    1390           It is not an error for a weak reference to remain
    1391           unsatisfied.
    1392
    1393           During linking, the value of an undefined weak reference is:
    1394           - Zero if the relocation type is absolute
    1395           - The address of the place if the relocation is pc-relative
    1396           - The address of nominal base address if the relocation
    1397             type is base-relative.
    1398        */
    1399
    1400        switch (type) {
            // 没有定义的弱引用,它的 sym_addr 是 0,或者重定位的时候不关心 sym_addr 的值
    1401#if defined(__arm__)
    1402          case R_ARM_JUMP_SLOT:
    1403          case R_ARM_GLOB_DAT:
    1404          case R_ARM_ABS32:
    1405          case R_ARM_RELATIVE:    /* Don't care. */
    1406            // sym_addr was initialized to be zero above or relocation
    1407            // code below does not care about value of sym_addr.
    1408            // No need to do anything.
    1409            break;
    1410#elif defined(__i386__)
    1411          case R_386_JMP_SLOT:
    1412          case R_386_GLOB_DAT:
    1413          case R_386_32:
    1414          case R_386_RELATIVE:    /* Don't care. */
    1415          case R_386_IRELATIVE:
    1416            // sym_addr was initialized to be zero above or relocation
    1417            // code below does not care about value of sym_addr.
    1418            // No need to do anything.
    1419            break;
    1420          case R_386_PC32:
    1421            sym_addr = reloc;
    1422            break;
    1423#endif
    1424
    1425#if defined(__arm__)
    1426          case R_ARM_COPY:
    1427            // Fall through. Can't really copy if weak symbol is not found at run-time.
    1428#endif
    1429          default:
    1430            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
    1431            return -1;
    1432        }
    1433      } else {
    1434        // 找到了符号的定义 so,计算该符号的地址
    1435        sym_addr = lsi->resolve_symbol_address(s);
    1436      }
    1437      count_relocation(kRelocSymbol);
    1438    }
    1439
    1440    switch (type) {
            // 根据重定位类型修改 reloc 处的值
    1441#if defined(__arm__)
    1442      case R_ARM_JUMP_SLOT:
    1443        count_relocation(kRelocAbsolute);
    1444        MARK(rel->r_offset);
    1445        TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
    1446        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
    1447        break;
    1448      case R_ARM_GLOB_DAT:
    1449        count_relocation(kRelocAbsolute);
    1450        MARK(rel->r_offset);
    1451        TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
    1452        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
    1453        break;
    1454      case R_ARM_ABS32:
    1455        count_relocation(kRelocAbsolute);
    1456        MARK(rel->r_offset);
    1457        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
    1458        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
    1459        break;
    1460      case R_ARM_REL32:
    1461        count_relocation(kRelocRelative);
    1462        MARK(rel->r_offset);
    1463        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
    1464                   reloc, sym_addr, rel->r_offset, sym_name);
    1465        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
    1466        break;
    1467      case R_ARM_COPY:
    1468        /*
    1469         * ET_EXEC is not supported so this should not happen.
    1470         *
    1471         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
    1472         *
    1473         * Section 4.7.1.10 "Dynamic relocations"
    1474         * R_ARM_COPY may only appear in executable objects where e_type is
    1475         * set to ET_EXEC.
    1476         */
    1477        DL_ERR("%s R_ARM_COPY relocations are not supported", name);
    1478        return -1;
    1479#elif defined(__i386__)
    1480      case R_386_JMP_SLOT:
    1481        count_relocation(kRelocAbsolute);
    1482        MARK(rel->r_offset);
    1483        TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
    1484        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
    1485        break;
    1486      case R_386_GLOB_DAT:
    1487        count_relocation(kRelocAbsolute);
    1488        MARK(rel->r_offset);
    1489        TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
    1490        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
    1491        break;
    1492      case R_386_32:
    1493        count_relocation(kRelocRelative);
    1494        MARK(rel->r_offset);
    1495        TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
    1496        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
    1497        break;
    1498      case R_386_PC32:
    1499        count_relocation(kRelocRelative);
    1500        MARK(rel->r_offset);
    1501        TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
    1502                   reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
    1503        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
    1504        break;
    1505#elif defined(__mips__)
    1506      case R_MIPS_REL32:
    1507#if defined(__LP64__)
    1508        // MIPS Elf64_Rel entries contain compound relocations
    1509        // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case
    1510        if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 ||
    1511            ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) {
    1512          DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)",
    1513                 type, (unsigned)ELF64_R_TYPE2(rel->r_info),
    1514                 (unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx);
    1515          return -1;
    1516        }
    1517#endif
    1518        count_relocation(kRelocAbsolute);
    1519        MARK(rel->r_offset);
    1520        TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc),
    1521                   static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*");
    1522        if (s) {
    1523          *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
    1524        } else {
    1525          *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
    1526        }
    1527        break;
    1528#endif
    1529
    1530#if defined(__arm__)
    1531      case R_ARM_RELATIVE:
    1532#elif defined(__i386__)
    1533      case R_386_RELATIVE:
    1534#endif
    1535        count_relocation(kRelocRelative);
    1536        MARK(rel->r_offset);
    1537        if (sym) {
    1538          DL_ERR("odd RELATIVE form...");
    1539          return -1;
    1540        }
    1541        TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p",
    1542                   reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
    1543        *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
    1544        break;
    1545#if defined(__i386__)
    1546      case R_386_IRELATIVE:
    1547        count_relocation(kRelocRelative);
    1548        MARK(rel->r_offset);
    1549        TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
    1550        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + *reinterpret_cast<ElfW(Addr)*>(reloc));
    1551        break;
    1552#endif
    1553
    1554      default:
    1555        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
    1556        return -1;
    1557    }
    1558  }
    1559  return 0;
    1560}
    Relocate()

                            soinfo_do_lookup()查找符号的定义 so

                            soinfo_do_lookup()源码:

    482static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) {
          // 计算符号的哈希值
    483  unsigned elf_hash = elfhash(name);
    484  ElfW(Sym)* s = nullptr;
    485
    486  /* "This element's presence in a shared object library alters the dynamic linker's
    487   * symbol resolution algorithm for references within the library. Instead of starting
    488   * a symbol search with the executable file, the dynamic linker starts from the shared
    489   * object itself. If the shared object fails to supply the referenced symbol, the
    490   * dynamic linker then searches the executable file and other shared objects as usual."
    491   *
    492   * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
    493   *
    494   * Note that this is unlikely since static linker avoids generating
    495   * relocations for -Bsymbolic linked dynamic executables.
    496   */
    497  if (si->has_DT_SYMBOLIC) {
    498    DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si->name, name);
    499    s = soinfo_elf_lookup(si, elf_hash, name);
    500    if (s != nullptr) {
    501      *lsi = si;
    502    }
    503  }
    504
    505  if (s == nullptr && somain != nullptr) {
    506    // 1. Look for it in the main executable unless we already did.
    507    if (si != somain || !si->has_DT_SYMBOLIC) {
    508      DEBUG("%s: looking up %s in executable %s",
    509            si->name, name, somain->name);
    510      s = soinfo_elf_lookup(somain, elf_hash, name);
    511      if (s != nullptr) {
    512        *lsi = somain;
    513      }
    514    }
    515
    516    // 2. Look for it in the ld_preloads
    517    if (s == nullptr) {
    518      for (int i = 0; g_ld_preloads[i] != NULL; i++) {
    519        s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name);
    520        if (s != nullptr) {
    521          *lsi = g_ld_preloads[i];
    522          break;
    523        }
    524      }
    525    }
    526  }
    527
    528  /* Look for symbols in the local scope (the object who is
    529   * searching). This happens with C++ templates on x86 for some
    530   * reason.
    531   *
    532   * Notes on weak symbols:
    533   * The ELF specs are ambiguous about treatment of weak definitions in
    534   * dynamic linking.  Some systems return the first definition found
    535   * and some the first non-weak definition.   This is system dependent.
    536   * Here we return the first definition found for simplicity.  */
    537
    538  if (s == nullptr && !si->has_DT_SYMBOLIC) {
            // 在其依赖库(子结点)中递归查找符号
    539    DEBUG("%s: looking up %s in local scope", si->name, name);
    540    s = soinfo_elf_lookup(si, elf_hash, name);
    541    if (s != nullptr) {
    542      *lsi = si;
    543    }
    544  }
    545
    546  if (s == nullptr) {
    547    si->get_children().visit([&](soinfo* child) {
    548      DEBUG("%s: looking up %s in %s", si->name, name, child->name);
    549      s = soinfo_elf_lookup(child, elf_hash, name);
    550      if (s != nullptr) {
    551        *lsi = child;
    552        return false;
    553      }
    554      return true;
    555    });
    556  }
    557
    558  if (s != nullptr) {
    559    TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
    560               "found in %s, base = %p, load bias = %p",
    561               si->name, name, reinterpret_cast<void*>(s->st_value),
    562               (*lsi)->name, reinterpret_cast<void*>((*lsi)->base),
    563               reinterpret_cast<void*>((*lsi)->load_bias));
    564  }
    565
    566  return s;
    567}
    soinfo_do_lookup()

                                soinfo_do_look()分别在其自身、 预加载库和依赖库中查找符号的定义,具体的查找函数是 soinfo_elf_lookup()

                                soinfo_elf_lookup()源码:

    418static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
    
             // 符号表
    
    419  ElfW(Sym)* symtab = si->symtab;
    420
    421  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd",
    422             name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
    423   // 通过哈希表在符号表中快速查找 name
    424  for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
    425    ElfW(Sym)* s = symtab + n;
            // 符号名字需相同
    426    if (strcmp(si->get_string(s->st_name), name)) continue;
    427
    428    // only concern ourselves with global and weak symbol definitions
    429    switch (ELF_ST_BIND(s->st_info)) {
    430      case STB_GLOBAL:
    431      case STB_WEAK:
    432        if (s->st_shndx == SHN_UNDEF) {
               // 符号未定义
    433          continue;
    434        }
    435
    436        TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
    437                 name, si->name, reinterpret_cast<void*>(s->st_value),
    438                 static_cast<size_t>(s->st_size));
               // 在 si 中找到符号的定义
    439        return s;
    440      case STB_LOCAL:
    441        continue;
    442      default:
    443        __libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'",
    444            ELF_ST_BIND(s->st_info), name, si->name);
    445    }
    446  }
    447
    448  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
    449             name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
    450
    451
    452  return nullptr;
    453}
    soinfo_elf_lookup()

     

                                Relocate()函数,在找到符号后,调用resolve_symbol_address() 来计算符号的地址 。

                                resolve_symbol_address() 源码

    如果符号的类型不是 STT_GNU_IFUNC(GNU indirect function),如STT_FUNC(可执行代码,如函数)、 STT_OBJECT(数据对象,如变量)等, 直接返回符号的地址,即 s->st_value  +  load_bias, 否者调用 call_ifunc_resolver()计算符号的地址

                           call_ifunc_resolver()源码:
    1072static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
    1073  typedef ElfW(Addr) (*ifunc_resolver_t)(void);
          // 将 resolver_addr 转为函数指针
    1074  ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
          // 执行 resoler_addr 处的函数
    1075  ElfW(Addr) ifunc_addr = ifunc_resolver();
    1076  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
    1077
    1078  return ifunc_addr;
    1079}
    call_ifunc_resolver()

    重定位类型与重定位值的计算方式对应表

    重定位类型

    reloc 处的值

    R_ARM_JUMP_SLOT

    *reloc = sym_addr

    R_ARM_GLOB_DAT

    *reloc = sym_addr

    R_ARM_ABS32

    *reloc += sym_addr

    R_ARM_REL32

    *reloc+= sym_addr - rel->r_offset

    R_ARM_RELATIVE

    *reloc += base

                                       

    至此,find_libraries()的第三部分分析完了。

    总结:遍历重定位表,根据重定项的 r_info 获得重定位类型和重定位项对应的符号在符号表中的索引;然后利用 so 中的 hash 表,根据符号名快速地查找符号在哪个 so中定义; 当找到了符号的定义,计算符号的地址 sym_addr;最后根据符号的重定位类型,结合 sym_addr 计算重定位值。

                                so 文件加载到内存,并链接完成后,就开始调用 so 中的初始化函数。回到 do_dlopen()继续分析。

      do_dlopen()的第二部分:

                         CallConstructors()进行初始化操作

                         CallConstructors()源码

    1656void soinfo::CallConstructors() {
    1657  if (constructors_called) {
    1658    return;
    1659  }
    1660
    1661  // We set constructors_called before actually calling the constructors, otherwise it doesn't
    1662  // protect against recursive constructor calls. One simple example of constructor recursion
    1663  // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
    1664  // 1. The program depends on libc, so libc's constructor is called here.
    1665  // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
    1666  // 3. dlopen() calls the constructors on the newly created
    1667  //    soinfo for libc_malloc_debug_leak.so.
    1668  // 4. The debug .so depends on libc, so CallConstructors is
    1669  //    called again with the libc soinfo. If it doesn't trigger the early-
    1670  //    out above, the libc constructor will be called again (recursively!).
    1671  constructors_called = true;
    1672
    1673  if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) {
    1674    // The GNU dynamic linker silently ignores these, but we warn the developer.
    1675    PRINT(""%s": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
    1676          name, preinit_array_count);
    1677  }
    1678
    1679  get_children().for_each([] (soinfo* si) {
    1680    si->CallConstructors();
    1681  });
    1682
    1683  TRACE(""%s": calling constructors", name);
    1684
    1685  // DT_INIT should be called before DT_INIT_ARRAY if both are present.
          // 调用 init_func 函数
    1686  CallFunction("DT_INIT", init_func);
          // 调用 init_array 数组中的函数
    1687  CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
    1688}
    CallConstructors()

    init_func 和init_array,这两个变量是在 PrelinkImage()中解析 dynamic  section 时赋值的。 通常加壳逻辑就放在 init_func 或 init_array 中,它们先于 jni_onLoad 执行。

  • 相关阅读:
    机器学习进阶-案例实战-答题卡识别判 1.cv2.getPerspectiveTransform(获得投射变化后的H矩阵) 2.cv2.warpPerspective(H获得变化后的图像) 3.cv2.approxPolyDP(近似轮廓) 4.cv2.threshold(二值变化) 7.cv2.countNonezeros(非零像素点个数)6.cv2.bitwise_and(与判断)
    机器学习进阶-案例实战-停车场车位识别-keras预测是否停车站有车
    机器学习进阶-案例实战-停车场车位识别
    Spark HA模式访问Hadoop HA下的数据
    Solr Cloud的搭建使用
    TensorFlow的安装
    spark-submit提交方式测试Demo
    时间迭代和BigDecimal操作
    TestCodis的工具代码
    Gson的应用测试
  • 原文地址:https://www.cnblogs.com/heixiang/p/10987838.html
Copyright © 2011-2022 走看看