Android 8.1.0源码分析SO加载执行流程

安卓逆向入门教程 6. 编写第一个so中知道,要想调用某个so库中的Native方法,需要将so库加载进来。

1
2
3
4
5
6
7
8
public class myJNI {
  //加载so库
static {
System.loadLibrary("JniTest");//so库名字,全称为libJniTest.so
}
  //native方法
public static native String sayHello();//调用so库中的sayHello()方法
}

可以看到在Java层加载so库用了System.loadLibrary()方法。其实加载一个so库,可以通过System.load()System.loadLibrary()来加载。System.loadLibrary()只能加载APK包中jniLibs目录下的so,而System.load()可以加载任意路径下的so,这两种方式最终都会调用Android底层的dlopen()来打开so。

推荐一个查看Android源码的网站,查看Android源码发现System.load()System.loadLibrary()/libcore/ojluni/src/main/java/java/lang/System.java中这样定义:

1
2
3
4
5
6
7
8
9
@CallerSensitive
public static void load(String filename) {
Runtime.getRuntime().load0(VMStack.getStackClass1(), filename);
}

@CallerSensitive
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);
}

随意跟进去看看,发现这两个方法都会调用到doLoad()

1. Java层

1.1 loadLibrary0()

loadLibrary()为例,进去loadLibrary0()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// /libcore/ojluni/src/main/java/java/lang/Runtime.java
synchronized void loadLibrary0(ClassLoader loader, String libname) {
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: " + libname);
}
String libraryName = libname;
if (loader != null) {
String filename = loader.findLibrary(libraryName);
if (filename == null) {
// It's not necessarily true that the ClassLoader used
// System.mapLibraryName, but the default setup does, and it's
// misleading to say we didn't find "libMyLibrary.so" when we
// actually searched for "liblibMyLibrary.so.so".
throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
System.mapLibraryName(libraryName) + "\"");
}
String error = doLoad(filename, loader);
if (error != null) {
throw new UnsatisfiedLinkError(error);
}
return;
}
String filename = System.mapLibraryName(libraryName);
List<String> candidates = new ArrayList<String>();
String lastError = null;
for (String directory : getLibPaths()) {
String candidate = directory + filename;
candidates.add(candidate);
if (IoUtils.canOpenReadOnly(candidate)) {
String error = doLoad(candidate, loader);
if (error == null) {
return; // We successfully loaded the library. Job done.
}
lastError = error;
}
}
if (lastError != null) {
throw new UnsatisfiedLinkError(lastError);
}
throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}

上面代码的流程如下:

  1. 若loader非空,则利用findLibrary()方法从ClassLoader中获取library的path;若loader为空,则利用System.mapLibraryName()方法获取library的name(比如传递“test”进来,返回的是“libtest.so”),然后利用getLibPaths()函数获取APK包的JniLibs目录的路径path。
  2. 得到library的path后,进入doLoad()方法。

1.2 doLoad()

在ClassLoader非空或空的情况下最终都得到了library的path,作为参数传入doLoad()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// /libcore/ojluni/src/main/java/java/lang/Runtime.java
private String doLoad(String name, ClassLoader loader) {
String librarySearchPath = null;
if (loader != null && loader instanceof BaseDexClassLoader) {
BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader;
librarySearchPath = dexClassLoader.getLdLibraryPath();
}
synchronized (this) {
return nativeLoad(name, loader, librarySearchPath);
}
}

private static native String nativeLoad(String filename, ClassLoader loader,
String librarySearchPath);
  • 若loader非空并且是BaseDexClassLoader的一个实例,通过getLdLibraryPath()方法将得到的所有路径用”:”连接形成字符串赋值到librarySearchPath,再调用nativeLoad()这个JNI方法;
1
2
3
4
5
6
7
8
9
10
11
12
// /libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
public String getLdLibraryPath() {
StringBuilder result = new StringBuilder();
for (File directory : pathList.getNativeLibraryDirectories()) {
if (result.length() > 0) {
result.append(':');
}
result.append(directory);
}

return result.toString();
}
1
2
3
4
// /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
public List<File> getNativeLibraryDirectories() {
return nativeLibraryDirectories;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
160 // Native libraries may exist in both the system and
161 // application library paths, and we use this search order:
162 //
163 // 1. This class loader's library path for application libraries (librarySearchPath):
164 // 1.1. Native library directories
165 // 1.2. Path to libraries in apk-files
166 // 2. The VM's library path from the system property for system libraries
167 // also known as java.library.path
168 //
169 // This order was reversed prior to Gingerbread; see http://b/2933456.
170 this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
171 this.systemNativeLibraryDirectories =
172 splitPaths(System.getProperty("java.library.path"), true);
173 List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
174 allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
175
176 this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories);

从注释中可以知道nativeLibraryDirectories会按照以上顺序取得。

  • 否则直接进入nativeLoad()方法。

2. JNI层

继续进入JNI层分析nativeLoad(),命名规则为“类名_方法名”。

2.1 Runtime_nativeLoad()

1
2
3
4
5
6
7
// /libcore/ojluni/src/main/native/Runtime.c
JNIEXPORT jstring JNICALL
Runtime_nativeLoad(JNIEnv* env, jclass ignored, jstring javaFilename,
jobject javaLoader, jstring javaLibrarySearchPath)
{
return JVM_NativeLoad(env, javaFilename, javaLoader, javaLibrarySearchPath);
}

2.2 JVM_NativeLoad()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// /art/runtime/openjdkjvm/OpenjdkJvm.cc
322JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
323 jstring javaFilename,
324 jobject javaLoader,
325 jstring javaLibrarySearchPath) {
326 ScopedUtfChars filename(env, javaFilename);
327 if (filename.c_str() == NULL) {
328 return NULL;
329 }
330
331 std::string error_msg;
332 {
333 art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();
334 bool success = vm->LoadNativeLibrary(env,
335 filename.c_str(),
336 javaLoader,
337 javaLibrarySearchPath,
338 &error_msg);
339 if (success) {
340 return nullptr;
341 }
342 }
343
344 // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
345 env->ExceptionClear();
346 return env->NewStringUTF(error_msg.c_str());
347}

如果filename(在loadLibrary0()中构造的路径)非空,则进入javaVM加载;否则打印异常。

2.3 LoadNativeLibrary()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// /art/runtime/java_vm_ext.cc
796bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
797 const std::string& path,
798 jobject class_loader,
799 jstring library_path,
800 std::string* error_msg) {
801 error_msg->clear();
802
803 // See if we've already loaded this library. If we have, and the class loader
804 // matches, return successfully without doing anything.
805 // TODO: for better results we should canonicalize the pathname (or even compare
806 // inodes). This implementation is fine if everybody is using System.loadLibrary.
807 SharedLibrary* library;
808 Thread* self = Thread::Current();
809 {
810 // TODO: move the locking (and more of this logic) into Libraries.
811 MutexLock mu(self, *Locks::jni_libraries_lock_);
812 library = libraries_->Get(path);
813 }
814 void* class_loader_allocator = nullptr;
815 {
816 ScopedObjectAccess soa(env);
817 // As the incoming class loader is reachable/alive during the call of this function,
818 // it's okay to decode it without worrying about unexpectedly marking it alive.
819 ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader);
820
821 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
822 if (class_linker->IsBootClassLoader(soa, loader.Ptr())) {
823 loader = nullptr;
824 class_loader = nullptr;
825 }
826
827 class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Ptr());
828 CHECK(class_loader_allocator != nullptr);
829 }
830 if (library != nullptr) {
831 // Use the allocator pointers for class loader equality to avoid unnecessary weak root decode.
832 if (library->GetClassLoaderAllocator() != class_loader_allocator) {
833 // The library will be associated with class_loader. The JNI
834 // spec says we can't load the same library into more than one
835 // class loader.
836 StringAppendF(error_msg, "Shared library \"%s\" already opened by "
837 "ClassLoader %p; can't open in ClassLoader %p",
838 path.c_str(), library->GetClassLoader(), class_loader);
839 LOG(WARNING) << error_msg;
840 return false;
841 }
842 VLOG(jni) << "[Shared library \"" << path << "\" already loaded in "
843 << " ClassLoader " << class_loader << "]";
844 if (!library->CheckOnLoadResult()) {
845 StringAppendF(error_msg, "JNI_OnLoad failed on a previous attempt "
846 "to load \"%s\"", path.c_str());
847 return false;
848 }
849 return true;
850 }
851
852 // Open the shared library. Because we're using a full path, the system
853 // doesn't have to search through LD_LIBRARY_PATH. (It may do so to
854 // resolve this library's dependencies though.)
855
856 // Failures here are expected when java.library.path has several entries
857 // and we have to hunt for the lib.
858
859 // Below we dlopen but there is no paired dlclose, this would be necessary if we supported
860 // class unloading. Libraries will only be unloaded when the reference count (incremented by
861 // dlopen) becomes zero from dlclose.
862
863 Locks::mutator_lock_->AssertNotHeld(self);
864 const char* path_str = path.empty() ? nullptr : path.c_str();
865 bool needs_native_bridge = false;
866 void* handle = android::OpenNativeLibrary(env,
867 runtime_->GetTargetSdkVersion(),
868 path_str,
869 class_loader,
870 library_path,
871 &needs_native_bridge,
872 error_msg);
873
874 VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]";
875
876 if (handle == nullptr) {
877 VLOG(jni) << "dlopen(\"" << path << "\", RTLD_NOW) failed: " << *error_msg;
878 return false;
879 }
880
881 if (env->ExceptionCheck() == JNI_TRUE) {
882 LOG(ERROR) << "Unexpected exception:";
883 env->ExceptionDescribe();
884 env->ExceptionClear();
885 }
886 // Create a new entry.
887 // TODO: move the locking (and more of this logic) into Libraries.
888 bool created_library = false;
889 {
890 // Create SharedLibrary ahead of taking the libraries lock to maintain lock ordering.
891 std::unique_ptr<SharedLibrary> new_library(
892 new SharedLibrary(env,
893 self,
894 path,
895 handle,
896 needs_native_bridge,
897 class_loader,
898 class_loader_allocator));
899
900 MutexLock mu(self, *Locks::jni_libraries_lock_);
901 library = libraries_->Get(path);
902 if (library == nullptr) { // We won race to get libraries_lock.
903 library = new_library.release();
904 libraries_->Put(path, library);
905 created_library = true;
906 }
907 }
908 if (!created_library) {
909 LOG(INFO) << "WOW: we lost a race to add shared library: "
910 << "\"" << path << "\" ClassLoader=" << class_loader;
911 return library->CheckOnLoadResult();
912 }
913 VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]";
914
915 bool was_successful = false;
916 void* sym = library->FindSymbol("JNI_OnLoad", nullptr);
917 if (sym == nullptr) {
918 VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";
919 was_successful = true;
920 } else {
921 // Call JNI_OnLoad. We have to override the current class
922 // loader, which will always be "null" since the stuff at the
923 // top of the stack is around Runtime.loadLibrary(). (See
924 // the comments in the JNI FindClass function.)
925 ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));
926 self->SetClassLoaderOverride(class_loader);
927
928 VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";
929 typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
930 JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
931 int version = (*jni_on_load)(this, nullptr);
932
933 if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {
934 // Make sure that sigchain owns SIGSEGV.
935 EnsureFrontOfChain(SIGSEGV);
936 }
937
938 self->SetClassLoaderOverride(old_class_loader.get());
939
940 if (version == JNI_ERR) {
941 StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str());
942 } else if (JavaVMExt::IsBadJniVersion(version)) {
943 StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in \"%s\": %d",
944 path.c_str(), version);
945 // It's unwise to call dlclose() here, but we can mark it
946 // as bad and ensure that future load attempts will fail.
947 // We don't know how far JNI_OnLoad got, so there could
948 // be some partially-initialized stuff accessible through
949 // newly-registered native method calls. We could try to
950 // unregister them, but that doesn't seem worthwhile.
951 } else {
952 was_successful = true;
953 }
954 VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure")
955 << " from JNI_OnLoad in \"" << path << "\"]";
956 }
957
958 library->SetResult(was_successful);
959 return was_successful;
960}

当sym==nullptr 的时候它直接返回true,这里是因为首次加载的时候,JNI_OnLoad 函数是首次执行,所以它首次加载。如果加载过了,就要找到加载过它的ClassLoader,并且拿到相关信息验证,信息无误之后才返回true。

2.4 OpenNativeLibrary()

根据参数溯源,来到OpenNativeLibrary()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// /system/core/libnativeloader/native_loader.cpp
523 void* OpenNativeLibrary(JNIEnv* env,
524 int32_t target_sdk_version,
525 const char* path,
526 jobject class_loader,
527 jstring library_path,
528 bool* needs_native_bridge,
529 std::string* error_msg) {
530 #if defined(__ANDROID__)
531 UNUSED(target_sdk_version);
532 if (class_loader == nullptr) {
533 *needs_native_bridge = false;
534 return dlopen(path, RTLD_NOW);
535 }
536
537 std::lock_guard<std::mutex> guard(g_namespaces_mutex);
538 NativeLoaderNamespace ns;
539
540 if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
541 // This is the case where the classloader was not created by ApplicationLoaders
542 // In this case we create an isolated not-shared namespace for it.
543 if (!g_namespaces->Create(env,
544 target_sdk_version,
545 class_loader,
546 false /* is_shared */,
547 false /* is_for_vendor */,
548 library_path,
549 nullptr,
550 &ns,
551 error_msg)) {
552 return nullptr;
553 }
554 }
555
556 if (ns.is_android_namespace()) {
557 android_dlextinfo extinfo;
558 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
559 extinfo.library_namespace = ns.get_android_ns();
560
561 void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
562 if (handle == nullptr) {
563 *error_msg = dlerror();
564 }
565 *needs_native_bridge = false;
566 return handle;
567 } else {
568 void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
569 if (handle == nullptr) {
570 *error_msg = NativeBridgeGetError();
571 }
572 *needs_native_bridge = true;
573 return handle;
574 }
575 #else
576 UNUSED(env, target_sdk_version, class_loader, library_path);
577 *needs_native_bridge = false;
578 void* handle = dlopen(path, RTLD_NOW);
579 if (handle == nullptr) {
580 if (NativeBridgeIsSupported(path)) {
581 *needs_native_bridge = true;
582 handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
583 if (handle == nullptr) {
584 *error_msg = NativeBridgeGetError();
585 }
586 } else {
587 *needs_native_bridge = false;
588 *error_msg = dlerror();
589 }
590 }
591 return handle;
592 #endif
593 }

这个函数无论怎样都会调用dlopen()函数。

2.5 dlopen()

我们选择的是bionic目录下的dlopen(),是因为在 bionic目录下都属于Android的内核源码,是比较关键的地方。

1
2
3
4
5
6
7
8
9
10
11
// /bionic/libdl/libdl.c
101 void* dlopen(const char* filename, int flag) {
102 const void* caller_addr = __builtin_return_address(0);
103 return __loader_dlopen(filename, flag, caller_addr);
104 }

23 // These functions are exported by the loader
24 // TODO(dimitry): replace these with reference to libc.so
25
26 __attribute__((__weak__, visibility("default")))
27 void* __loader_dlopen(const char* filename, int flags, const void* caller_addr);

2.6 __dlopen()

继续搜索__loader_dlopen,在/bionic/linker/dlfcn.cpp中指向了__dlopen

1
2
3
102  void* __dlopen(const char* filename, int flags, const void* caller_addr) {
103 return dlopen_ext(filename, flags, nullptr, caller_addr);
104 }

2.7 dlopen_ext()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// /bionic/linker/dlfcn.cpp
81 static void* dlopen_ext(const char* filename,
82 int flags,
83 const android_dlextinfo* extinfo,
84 const void* caller_addr) {
85 ScopedPthreadMutexLocker locker(&g_dl_mutex);
86 g_linker_logger.ResetState();
87 void* result = do_dlopen(filename, flags, extinfo, caller_addr);
88 if (result == nullptr) {
89 __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
90 return nullptr;
91 }
92 return result;
93 }

2.8 do_dlopen()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// /bionic/linker/linker.cpp
1937 void* do_dlopen(const char* name, int flags,
1938 const android_dlextinfo* extinfo,
1939 const void* caller_addr) {
1940 std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
1941 ScopedTrace trace(trace_prefix.c_str());
1942 ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
1943 soinfo* const caller = find_containing_library(caller_addr);
1944 android_namespace_t* ns = get_caller_namespace(caller);
...
2012 ProtectedDataGuard guard;
2013 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
2014 loading_trace.End();
2015
2016 if (si != nullptr) {
2017 void* handle = si->to_handle();
2018 LD_LOG(kLogDlopen,
2019 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
2020 si->get_realpath(), si->get_soname(), handle);
2021 si->call_constructors();
2022 failure_guard.Disable();
2023 LD_LOG(kLogDlopen,
2024 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
2025 si->get_realpath(), si->get_soname(), handle);
2026 return handle;
2027 }
2028
2029 return nullptr;
2030 }

2.9 find_library()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// /bionic/linker/linker.cpp
1714 static soinfo* find_library(android_namespace_t* ns,
1715 const char* name, int rtld_flags,
1716 const android_dlextinfo* extinfo,
1717 soinfo* needed_by) {
1718 soinfo* si;
1719
1720 // readers_map is shared across recursive calls to find_libraries.
1721 // However, the map is not shared across different threads.
1722 std::unordered_map<const soinfo*, ElfReader> readers_map;
1723 if (name == nullptr) {
1724 si = solist_get_somain();
1725 } else if (!find_libraries(ns,
1726 needed_by,
1727 &name,
1728 1,
1729 &si,
1730 nullptr,
1731 0,
1732 rtld_flags,
1733 extinfo,
1734 false /* add_as_children */,
1735 true /* search_linked_namespaces */,
1736 readers_map)) {
1737 return nullptr;
1738 }
1739
1740 si->increment_ref_count();
1741
1742 return si;
1743 }

2.10 find_libraries()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// /bionic/linker/linker.cpp
1497 bool find_libraries(android_namespace_t* ns,
1498 soinfo* start_with,
1499 const char* const library_names[],
1500 size_t library_names_count,
1501 soinfo* soinfos[],
1502 std::vector<soinfo*>* ld_preloads,
1503 size_t ld_preloads_count,
1504 int rtld_flags,
1505 const android_dlextinfo* extinfo,
1506 bool add_as_children,
1507 bool search_linked_namespaces,
1508 std::unordered_map<const soinfo*, ElfReader>& readers_map,
1509 std::vector<android_namespace_t*>* namespaces) {
...
1557 // try to find the load.
1558 // Note: start from the namespace that is stored in the LoadTask. This namespace
1559 // is different from the current namespace when the LoadTask is for a transitive
1560 // dependency and the lib that created the LoadTask is not found in the
1561 // current namespace but in one of the linked namespace.
1562 if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()),
1563 task,
1564 &zip_archive_cache,
1565 &load_tasks,
1566 rtld_flags,
1567 search_linked_namespaces || is_dt_needed)) {
1568 return false;
1569 }
...
1592 // Step 2: Load libraries in random order (see b/24047022)
1593 LoadTaskList load_list;
1594 for (auto&& task : load_tasks) {
1595 soinfo* si = task->get_soinfo();
1596 auto pred = [&](const LoadTask* t) {
1597 return t->get_soinfo() == si;
1598 };
1599
1600 if (!si->is_linked() &&
1601 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1602 load_list.push_back(task);
1603 }
1604 }
1605 shuffle(&load_list);
1606
1607 for (auto&& task : load_list) {
1608 if (!task->load()) {
1609 return false;
1610 }
1611 }
1612
1613 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1614 for (auto&& task : load_tasks) {
1615 soinfo* si = task->get_soinfo();
1616 if (!si->is_linked() && !si->prelink_image()) {
1617 return false;
1618 }
1619 }
...
1689 soinfo_list_t global_group = ns->get_global_group();
1690 bool linked = local_group.visit([&](soinfo* si) {
1691 if (!si->is_linked()) {
1692 if (!si->link_image(global_group, local_group, extinfo) ||
1693 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
1694 return false;
1695 }
1696 }
1697
1698 return true;
1699 });
1700
...
1689 soinfo_list_t global_group = ns->get_global_group();
1690 bool linked = local_group.visit([&](soinfo* si) {
1691 if (!si->is_linked()) {
1692 if (!si->link_image(global_group, local_group, extinfo) ||
1693 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
1694 return false;
1695 }
1696 }
...
1712 }

2.11 find_library_internal()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// /bionic/linker/linker.cpp
1431 static bool find_library_internal(android_namespace_t* ns,
1432 LoadTask* task,
1433 ZipArchiveCache* zip_archive_cache,
1434 LoadTaskList* load_tasks,
1435 int rtld_flags,
1436 bool search_linked_namespaces) {
1437 soinfo* candidate;
1438
1439 if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {//根据so的名称查找在soInfo的链表中查找是否已经存在
1440 task->set_soinfo(candidate);
1441 return true;
1442 }
1443
1444 // Library might still be loaded, the accurate detection
1445 // of this fact is done by load_library.
1446 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
1447 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
1448
1449 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {//如果不存在,说明还没加载,继续调用load_library 加载so
1450 return true;
1451 }
1452
1453 if (search_linked_namespaces) {
1454 // if a library was not found - look into linked namespaces
1455 for (auto& linked_namespace : ns->linked_namespaces()) {
1456 if (find_library_in_linked_namespace(linked_namespace,
1457 task)) {
1458 if (task->get_soinfo() == nullptr) {
1459 // try to load the library - once namespace boundary is crossed
1460 // we need to load a library within separate load_group
1461 // to avoid using symbols from foreign namespace while.
1462 //
1463 // However, actual linking is deferred until when the global group
1464 // is fully identified and is applied to all namespaces.
1465 // Otherwise, the libs in the linked namespace won't get symbols from
1466 // the global group.
1467 if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
1468 return true;
1469 }
1470 // lib was not found in the namespace. Try next linked namespace.
1471 } else {
1472 // lib is already loaded
1473 return true;
1474 }
1475 }
1476 }
1477 }
1478
1479 return false;
1480 }

2.12 load_library()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// /bionic/linker/linker.cpp
1311 static bool load_library(android_namespace_t* ns,
1312 LoadTask* task,
1313 ZipArchiveCache* zip_archive_cache,
1314 LoadTaskList* load_tasks,
1315 int rtld_flags,
1316 bool search_linked_namespaces) {
1317 const char* name = task->get_name();
1318 soinfo* needed_by = task->get_needed_by();
1319 const android_dlextinfo* extinfo = task->get_extinfo();
1320
1321 off64_t file_offset;
1322 std::string realpath;
1323 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
1324 file_offset = 0;
1325 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1326 file_offset = extinfo->library_fd_offset;
1327 }
1328
1329 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1330 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1331 "Will use given name.", name);
1332 realpath = name;
1333 }
1334
1335 task->set_fd(extinfo->library_fd, false);
1336 task->set_file_offset(file_offset);
1337 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
1338 }
1339
1340 // Open the file.
1341 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
1342 if (fd == -1) {
1343 DL_ERR("library \"%s\" not found", name);
1344 return false;
1345 }
1346
1347 task->set_fd(fd, true);
1348 task->set_file_offset(file_offset);
1349
1350 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
1351 }

2.13 load_library()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// /bionic/linker/linker.cpp
1178 static bool load_library(android_namespace_t* ns,
1179 LoadTask* task,
1180 LoadTaskList* load_tasks,
1181 int rtld_flags,
1182 const std::string& realpath,
1183 bool search_linked_namespaces) {
...
1276 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
1277 if (si == nullptr) {
1278 return false;
1279 }
1280
1281 task->set_soinfo(si);
1282
1283 // Read the ELF header and some of the segments.
1284 if (!task->read(realpath.c_str(), file_stat.st_size)) {
1285 soinfo_free(si);
1286 task->set_soinfo(nullptr);
1287 return false;
1288 }
1289
1290 // find and set DT_RUNPATH and dt_soname
1291 // Note that these field values are temporary and are
1292 // going to be overwritten on soinfo::prelink_image
1293 // with values from PT_LOAD segments.
1294 const ElfReader& elf_reader = task->get_elf_reader();
1295 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1296 if (d->d_tag == DT_RUNPATH) {
1297 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1298 }
1299 if (d->d_tag == DT_SONAME) {
1300 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1301 }
1302 }
1303
1304 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1305 load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
1306 });
1307
1308 return true;
1309 }

2.14 read()

1
2
3
4
5
// /bionic/linker/linker.cpp
635 bool read(const char* realpath, off64_t file_size) {
636 ElfReader& elf_reader = get_elf_reader();
637 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
638 }

2.15 ElfReader::Read()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// /bionic/linker/linker_phdr.cpp
149 bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file_size) {
150 if (did_read_) {
151 return true;
152 }
153 name_ = name;
154 fd_ = fd;
155 file_offset_ = file_offset;
156 file_size_ = file_size;
157
158 if (ReadElfHeader() &&//读elf文件头
159 VerifyElfHeader() &&//校验elf文件头
160 ReadProgramHeaders() &&//读程序头表
161 ReadSectionHeaders() &&//读节头表
162 ReadDynamicSection()) {//读动态节区
163 did_read_ = true;
164 }
165
166 return did_read_;
167 }

2.16 load()

回调到find_libraries(),继续往下执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// /bionic/linker/linker.cpp
640 bool load() {//装载so,并给soInfo结构体赋值
641 ElfReader& elf_reader = get_elf_reader();
642 if (!elf_reader.Load(extinfo_)) {
643 return false;
644 }
645
646 si_->base = elf_reader.load_start();
647 si_->size = elf_reader.load_size();
648 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
649 si_->load_bias = elf_reader.load_bias();
650 si_->phnum = elf_reader.phdr_count();
651 si_->phdr = elf_reader.loaded_phdr();
652
653 return true;
654 }

2.17 ElfReader::Load()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// /bionic/linker/linker_phdr.cpp
169 bool ElfReader::Load(const android_dlextinfo* extinfo) {
170 CHECK(did_read_);
171 if (did_load_) {
172 return true;
173 }
174 if (ReserveAddressSpace(extinfo) &&//为段开辟内存空间
175 LoadSegments() &&//加载段,这里是很好的脱壳点
176 FindPhdr()) {//设置程序的加载地址
177 did_load_ = true;
178 }
179
180 return did_load_;
181 }

继续回调到find_libraries()soinfo::prelink_image()函数的作用是解析linker文件中dynamic段的各项,例如重定位表,符号表。它大都是switch…case…结构,根据不同的tag做不同的解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// /bionic/linker/linker.cpp
2864 bool soinfo::prelink_image() {
2865 /* Extract dynamic section */
2866 ElfW(Word) dynamic_flags = 0;
2867 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
...
2897 uint32_t needed_count = 0;
2898 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2899 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2900 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2901 switch (d->d_tag) {
2902 case DT_SONAME:
2903 // this is parsed after we have strtab initialized (see below).
2904 break;
2905
2906 case DT_HASH:
2907 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2908 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2909 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2910 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
2911 break;
2912
2913 case DT_GNU_HASH:
2914 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2915 // skip symndx
2916 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2917 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
2918
2919 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
2920 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
2921 // amend chain for symndx = header[1]
2922 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2923 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2924
2925 if (!powerof2(gnu_maskwords_)) {
2926 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
2927 gnu_maskwords_, get_realpath());
2928 return false;
2929 }
2930 --gnu_maskwords_;
2931
2932 flags_ |= FLAG_GNU_HASH;
2933 break;
2934
2935 case DT_STRTAB:
2936 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
2937 break;
2938
2939 case DT_STRSZ:
2940 strtab_size_ = d->d_un.d_val;
2941 break;
...

继续回调find_libraries(),解析完后就是重定位了,soinfo::link_image()的作用是修复内存中的数据,完成重定位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// /bionic/linker/linker.cpp
3303 bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3304 const android_dlextinfo* extinfo) {
...
3344 if (android_relocs_ != nullptr) {
3345 // check signature
3346 if (android_relocs_size_ > 3 &&
3347 android_relocs_[0] == 'A' &&
3348 android_relocs_[1] == 'P' &&
3349 android_relocs_[2] == 'S' &&
3350 android_relocs_[3] == '2') {
3351 DEBUG("[ android relocating %s ]", get_realpath());
3352
3353 bool relocated = false;
3354 const uint8_t* packed_relocs = android_relocs_ + 4;
3355 const size_t packed_relocs_size = android_relocs_size_ - 4;
3356
3357 relocated = relocate(
3358 version_tracker,
3359 packed_reloc_iterator<sleb128_decoder>(
3360 sleb128_decoder(packed_relocs, packed_relocs_size)),
3361 global_group, local_group);
3362
3363 if (!relocated) {
3364 return false;
3365 }
3366 } else {
3367 DL_ERR("bad android relocation header.");
3368 return false;
3369 }
3370 }
...

2.20 relocate()

根据不同的条件给relocate()函数传入不同的参数。relocate()函数内部同样也是switch…case…结构,根据不同的type修改reloc表、符号表等,还有修改系统函数、全局/静态变量的绝对地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// /bionic/linker/linker.cpp
2497 template<typename ElfRelIteratorT>
2498 bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2499 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
2500 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2501 const auto rel = rel_iterator.next();
2502 if (rel == nullptr) {
2503 return false;
2504 }
2505
2506 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2507 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2508
2509 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
2510 ElfW(Addr) sym_addr = 0;
2511 const char* sym_name = nullptr;
2512 ElfW(Addr) addend = get_addend(rel, reloc);
...
2620 switch (type) {
2621 case R_GENERIC_JUMP_SLOT:
2622 count_relocation(kRelocAbsolute);
2623 MARK(rel->r_offset);
2624 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2625 reinterpret_cast<void*>(reloc),
2626 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2627
2628 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
2629 break;
2630 case R_GENERIC_GLOB_DAT:
2631 count_relocation(kRelocAbsolute);
2632 MARK(rel->r_offset);
2633 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2634 reinterpret_cast<void*>(reloc),
2635 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2636 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
2637 break;
2638 case R_GENERIC_RELATIVE:
2639 count_relocation(kRelocRelative);
2640 MARK(rel->r_offset);
2641 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2642 reinterpret_cast<void*>(reloc),
2643 reinterpret_cast<void*>(load_bias + addend));
2644 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
2645 break;
...

2.21 call_constructors()

回调到do_dlopen(),执行call_constructors()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// /bionic/linker/linker_soinfo.cpp
388 void soinfo::call_constructors() {
389 if (constructors_called) {
390 return;
391 }
392
393 // We set constructors_called before actually calling the constructors, otherwise it doesn't
394 // protect against recursive constructor calls. One simple example of constructor recursion
395 // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
396 // 1. The program depends on libc, so libc's constructor is called here.
397 // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
398 // 3. dlopen() calls the constructors on the newly created
399 // soinfo for libc_malloc_debug_leak.so.
400 // 4. The debug .so depends on libc, so CallConstructors is
401 // called again with the libc soinfo. If it doesn't trigger the early-
402 // out above, the libc constructor will be called again (recursively!).
403 constructors_called = true;
404
405 if (!is_main_executable() && preinit_array_ != nullptr) {
406 // The GNU dynamic linker silently ignores these, but we warn the developer.
407 PRINT("\"%s\": ignoring DT_PREINIT_ARRAY in shared library!", get_realpath());
408 }
409
410 get_children().for_each([] (soinfo* si) {
411 si->call_constructors();
412 });
413
414 if (!is_linker()) {
415 bionic_trace_begin((std::string("calling constructors: ") + get_realpath()).c_str());
416 }
417
418 // DT_INIT should be called before DT_INIT_ARRAY if both are present.
419 call_function("DT_INIT", init_func_, get_realpath());
420 call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false, get_realpath());
421
422 if (!is_linker()) {
423 bionic_trace_end();
424 }
425 }

2.22 call_function()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// /bionic/linker/linker_soinfo.cpp
346 static void call_function(const char* function_name __unused,
347 linker_dtor_function_t function,
348 const char* realpath __unused) {
349 if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
350 return;
351 }
352
353 TRACE("[ Calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
354 function();
355 TRACE("[ Done calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
356 }
357
358 template <typename F>
359 static void call_array(const char* array_name __unused,
360 F* functions,
361 size_t count,
362 bool reverse,
363 const char* realpath) {
364 if (functions == nullptr) {
365 return;
366 }
367
368 TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, realpath);
369
370 int begin = reverse ? (count - 1) : 0;
371 int end = reverse ? -1 : count;
372 int step = reverse ? -1 : 1;
373
374 for (int i = begin; i != end; i += step) {
375 TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
376 call_function("function", functions[i], realpath);
377 }
378
379 TRACE("[ Done calling %s for '%s' ]", array_name, realpath);
380 }

3. 总结

大致流程如下(从linker层开始):

  1. Linker优先从内存中查找已加载的SO,如果SO已加载,则直接返回handle。
  2. 如果SO没有加载,需要新建soinfo结构体,并将SO加载到内存。
  3. 执行预加载prelink_image(),读取SO中dynamic字段中的内容,初始化重定位需要的数据。
  4. 执行link_image(),修复内存中的数据,完成重定位。
  5. 执行SO中的Init以及Initarray中的函数。