一、Java层加载so文件
Android在Java层加载so的接口是System.loadLibrary()逐级调用的过程:
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目录下\sources\android-18文件夹)
Ctrl+左键 Runtime.getRuntime().loadLibrary() 中的 loadLibrary跟踪
系统重载了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 }
其中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 }
nativeLoad()用来加载name指向的so文件,nativeLoad()是Runtime类的一个native函数,在native层对应Runtime_nativeLoad()。
至此Java层的so文件加载跟踪完。根据nativeLoad进入Native层跟踪
二、nativeload开始 Native层的调用
Nativeload函数分析图
分三个阶段:
1. so文件加载
在java_lang_Runtime.cc文件中
可知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}
根据代码加载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()函数执行过程:
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}
根据代码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}
find_library()得到soinfo对象,分析源码需要跟踪find_library()和CallConstructors(),根据代码顺序继续分析
do_dlopen()总共两部分
do_dlopen()的第一部分:
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_libraries()的参数:/bionic/linker/linker.cpp
find_libraries()参数:
const char* const library_names[], //so文件名的数组
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()对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}
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()分三个部分:
第一部分:打开.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}
根据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}
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}
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}
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
加载完.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}
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};
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}
至此, 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}
对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}
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_look()分别在其自身、 预加载库和依赖库中查找符号的定义,具体的查找函数是 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}
Relocate()函数,在找到符号后,调用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}
重定位类型与重定位值的计算方式对应表
重定位类型 |
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}
init_func 和init_array,这两个变量是在 PrelinkImage()中解析 dynamic section 时赋值的。 通常加壳逻辑就放在 init_func 或 init_array 中,它们先于 jni_onLoad 执行。