14 | using return_type_trait_t = typename return_type_trait::type;
15 |
16 | template
17 | struct return_type_object_trait;
18 |
19 | template
20 | struct return_type_object_trait {
21 | using type = Return;
22 | };
23 | template
24 | using return_type_object_trait_t = typename return_type_object_trait::type;
25 |
26 | template
27 | struct member_type_trait;
28 |
29 | template
30 | struct member_type_trait {
31 | using type = Type;
32 | };
33 |
34 | template
35 | struct member_type_trait {
36 | using type = const char *;
37 | };
38 |
39 | template
40 | struct member_type_trait {
41 | using type = const char *;
42 | };
43 |
44 | template
45 | using member_type_trait_t = typename member_type_trait::type;
46 |
47 | template
48 | struct member_ref_type_trait;
49 |
50 | template
51 | struct member_ref_type_trait {
52 | using type = typename std::add_lvalue_reference_t;
53 | };
54 |
55 | template
56 | using member_ref_type_trait_t = typename member_ref_type_trait::type;
57 |
58 | template
59 | struct const_member_ref_type_trait;
60 |
61 | template
62 | struct const_member_ref_type_trait {
63 | using type = std::add_lvalue_reference_t>;
64 | };
65 |
66 | template
67 | using const_member_ref_type_trait_t = typename const_member_ref_type_trait::type;
--------------------------------------------------------------------------------
/library/src/main/cpp/include/fakelinker/unique_fd.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | template
9 | class unique_fd_impl final {
10 | public:
11 | unique_fd_impl() {}
12 |
13 | explicit unique_fd_impl(int fd) { reset(fd); }
14 |
15 | ~unique_fd_impl() { reset(); }
16 |
17 | unique_fd_impl(const unique_fd_impl &) = delete;
18 | void operator=(const unique_fd_impl &) = delete;
19 |
20 | unique_fd_impl(unique_fd_impl &&other) noexcept { reset(other.release()); }
21 |
22 | unique_fd_impl &operator=(unique_fd_impl &&s) noexcept {
23 | int fd = s.fd_;
24 | s.fd_ = -1;
25 | reset(fd, &s);
26 | return *this;
27 | }
28 |
29 | [[clang::reinitializes]] void reset(int new_value = -1) { reset(new_value, nullptr); }
30 |
31 | int get() const { return fd_; }
32 |
33 | bool operator>=(int rhs) const { return get() >= rhs; }
34 |
35 | bool operator<(int rhs) const { return get() < rhs; }
36 |
37 | bool operator==(int rhs) const { return get() == rhs; }
38 |
39 | bool operator!=(int rhs) const { return get() != rhs; }
40 |
41 | bool operator==(const unique_fd_impl &rhs) const { return get() == rhs.get(); }
42 |
43 | bool operator!=(const unique_fd_impl &rhs) const { return get() != rhs.get(); }
44 |
45 | // Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
46 | bool operator!() const = delete;
47 |
48 | bool ok() const { return get() >= 0; }
49 |
50 | int release() __attribute__((warn_unused_result)) {
51 | tag(fd_, this, nullptr);
52 | int ret = fd_;
53 | fd_ = -1;
54 | return ret;
55 | }
56 |
57 | private:
58 | void reset(int new_value, void *previous_tag) {
59 | int previous_errno = errno;
60 |
61 | if (fd_ != -1) {
62 | close(fd_, this);
63 | }
64 |
65 | fd_ = new_value;
66 | if (new_value != -1) {
67 | tag(new_value, previous_tag, this);
68 | }
69 |
70 | errno = previous_errno;
71 | }
72 |
73 | int fd_ = -1;
74 |
75 | // Template magic to use Closer::Tag if available, and do nothing if not.
76 | // If Closer::Tag exists, this implementation is preferred, because int is a
77 | // better match. If not, this implementation is SFINAEd away, and the no-op
78 | // below is the only one that exists.
79 | template
80 | static auto tag(int fd, void *old_tag, void *new_tag) -> decltype(T::Tag(fd, old_tag, new_tag), void()) {
81 | T::Tag(fd, old_tag, new_tag);
82 | }
83 |
84 | template
85 | static void tag(long, void *, void *) {
86 | // No-op.
87 | }
88 |
89 | // Same as above, to select between Closer::Close(int) and Closer::Close(int,
90 | // void*).
91 | template
92 | static auto close(int fd, void *tag_value) -> decltype(T::Close(fd, tag_value), void()) {
93 | T::Close(fd, tag_value);
94 | }
95 |
96 | template
97 | static auto close(int fd, void *) -> decltype(T::Close(fd), void()) {
98 | T::Close(fd);
99 | }
100 | };
101 |
102 | // The actual details of closing are factored out to support unusual cases.
103 | // Almost everyone will want this DefaultCloser, which handles fdsan on bionic.
104 | struct DefaultCloser {
105 | static void Close(int fd) {
106 | // Even if close(2) fails with EINTR, the fd will have been closed.
107 | // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
108 | // else's fd.
109 | // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
110 | close(fd);
111 | }
112 | };
113 |
114 | // A wrapper type that can be implicitly constructed from either int or
115 | // unique_fd. This supports cases where you don't actually own the file
116 | // descriptor, and can't take ownership, but are temporarily acting as if
117 | // you're the owner.
118 | //
119 | // One example would be a function that needs to also allow
120 | // STDERR_FILENO, not just a newly-opened fd. Another example would be JNI code
121 | // that's using a file descriptor that's actually owned by a
122 | // ParcelFileDescriptor or whatever on the Java side, but where the JNI code
123 | // would like to enforce this weaker sense of "temporary ownership".
124 | //
125 | // If you think of unique_fd as being like std::string in that represents
126 | // ownership, borrowed_fd is like std::string_view (and int is like const
127 | // char*).
128 | struct borrowed_fd {
129 | /* implicit */ borrowed_fd(int fd) : fd_(fd) {} // NOLINT
130 |
131 | template
132 | /* implicit */ borrowed_fd(const unique_fd_impl &ufd) : fd_(ufd.get()) {} // NOLINT
133 |
134 | int get() const { return fd_; }
135 |
136 | bool operator>=(int rhs) const { return get() >= rhs; }
137 |
138 | bool operator<(int rhs) const { return get() < rhs; }
139 |
140 | bool operator==(int rhs) const { return get() == rhs; }
141 |
142 | bool operator!=(int rhs) const { return get() != rhs; }
143 |
144 | private:
145 | int fd_ = -1;
146 | };
147 |
148 | using unique_fd = unique_fd_impl;
149 |
150 | bool ReadFileToString(const std::string &path, std::string *content, bool follow_symlinks = false);
151 |
152 | bool ReadFdToString(borrowed_fd fd, std::string *content);
--------------------------------------------------------------------------------
/library/src/main/cpp/include/fakelinker/unique_memory.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class unique_memory {
6 | public:
7 | unique_memory() {}
8 |
9 | unique_memory(size_t size, bool check = false);
10 |
11 | unique_memory(void *ptr, size_t size = 0, bool is_mmap = false) : size_(size), is_mmap_(is_mmap) { reset(ptr); }
12 |
13 | ~unique_memory() { reset(); }
14 |
15 | unique_memory(unique_memory &&other) noexcept { reset(other.release()); }
16 |
17 | unique_memory &operator=(unique_memory &&s) noexcept {
18 | void *v = s.ptr_;
19 | s.ptr_ = nullptr;
20 | size_ = s.size_;
21 | s.size_ = 0;
22 | reset(v);
23 | return *this;
24 | }
25 |
26 | bool ok() { return ptr_ != nullptr; }
27 |
28 | char *char_ptr() { return reinterpret_cast(ptr_); }
29 |
30 | template
31 | T *get() {
32 | return reinterpret_cast(ptr_);
33 | }
34 |
35 | template
36 | T *release() {
37 | T *v = reinterpret_cast(ptr_);
38 | ptr_ = nullptr;
39 | size_ = 0;
40 | return v;
41 | }
42 |
43 | void reset(void *ptr = nullptr, size_t size = 0, bool is_mmap = false);
44 |
45 | size_t size() { return size_; }
46 |
47 | void clean();
48 |
49 | template
50 | void set(const size_t index, T value) {
51 | get()[index] = value;
52 | }
53 |
54 | private:
55 | void *ptr_ = nullptr;
56 | size_t size_ = 0;
57 | bool is_mmap_ = false;
58 | };
--------------------------------------------------------------------------------
/library/src/main/cpp/installer/hook_installer.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/11/8.
3 | //
4 | #include "hook_installer.h"
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | static uid_t set_uid = 1000;
21 | static gid_t set_gid = 1000;
22 | const char *lib_xattr = "u:object_r:system_file:s0";
23 | const char *file_xattr = "u:object_r:system_file:s0";
24 |
25 | int g_log_level = 5;
26 |
27 | int SetFileXattr(const char *path, const char *value) {
28 | if (access("/sys/fs/selinux", F_OK)) {
29 | return 0;
30 | }
31 | return syscall(__NR_setxattr, path, "security.selinux", value, strlen(value), 0);
32 | }
33 |
34 | static bool CreateDir(const char *dir) {
35 | char *parent = dirname(dir);
36 | char *copy = strdup(parent);
37 | if (copy != nullptr && access(copy, F_OK) != 0) {
38 | bool create = CreateDir(copy);
39 | if (!create) {
40 | return false;
41 | }
42 | }
43 | if (opendir(dir) == nullptr) {
44 | int ret = mkdir(dir, 00777);
45 | if (ret == -1) {
46 | LOGE("native create dir error: %s", dir);
47 | return false;
48 | }
49 | chown(dir, set_uid, set_gid);
50 | }
51 | return true;
52 | }
53 |
54 | static bool CopyFile(const char *dst, const char *src) {
55 | FILE *f1, *f2;
56 | int c;
57 |
58 | f1 = fopen(src, "rb");
59 | f2 = fopen(dst, "wb");
60 | if (f1 == nullptr || f2 == nullptr) {
61 | LOGE("read/write file error,src: %s, dst: %s", src, dst);
62 | return false;
63 | }
64 | while ((c = fgetc(f1)) != EOF) {
65 | fputc(c, f2);
66 | }
67 | fclose(f1);
68 | fclose(f2);
69 | return true;
70 | }
71 |
72 | int RemoveDir(const char *path) {
73 | DIR *dir;
74 | struct dirent *dp;
75 | char tmp_path[1024];
76 | int result = 0;
77 |
78 | dir = opendir(path);
79 | if (dir == nullptr) {
80 | return errno;
81 | }
82 | while ((dp = readdir(dir)) != nullptr) {
83 | if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
84 | strcpy(tmp_path, path);
85 | strcat(tmp_path, "/");
86 | strcat(tmp_path, dp->d_name);
87 | if (dp->d_type == DT_REG) {
88 | if (remove(tmp_path)) {
89 | result = errno;
90 | goto end;
91 | }
92 | } else if (dp->d_type == DT_DIR) {
93 | result = RemoveDir(tmp_path);
94 | if (result != 0) {
95 | goto end;
96 | }
97 | }
98 | }
99 | }
100 | end:
101 | closedir(dir);
102 | if (result == 0) {
103 | remove(path);
104 | }
105 | return result;
106 | }
107 |
108 | static int Uninstall(int len, char **argv) {
109 | int result = 0;
110 | struct stat buf;
111 |
112 | for (int i = 0; i < len; ++i) {
113 | LOGD("uninstall file: %s", argv[i]);
114 | if (access(argv[i], F_OK)) {
115 | continue;
116 | }
117 | result = stat(argv[i], &buf);
118 | if (result != 0) {
119 | return errno;
120 | }
121 | if (S_ISDIR(buf.st_mode)) {
122 | result = RemoveDir(argv[i]);
123 | if (result != 0) {
124 | return result;
125 | }
126 | } else if (S_ISREG(buf.st_mode)) {
127 | result = remove(argv[i]);
128 | if (result != 0) {
129 | return result;
130 | }
131 | }
132 | }
133 | return result;
134 | }
135 |
136 | C_API API_PUBLIC int main(int argc, char **argv) {
137 | int index = 1;
138 | if (!strcmp(argv[index], "remove")) {
139 | return Uninstall(argc - 2, &argv[++index]);
140 | }
141 | if (strcmp(argv[index], "copy") != 0) {
142 | LOGE("error operation type: %s", argv[index]);
143 | printf("exit code -1");
144 | return -1;
145 | }
146 | set_uid = strtol(argv[++index], nullptr, 0);
147 | set_gid = strtol(argv[++index], nullptr, 0);
148 | bool lib = strcmp(argv[++index], "lib") == 0;
149 | if (lib) {
150 | lib_xattr = argv[++index];
151 | } else {
152 | file_xattr = argv[++index];
153 | }
154 | if (!CreateDir(argv[++index])) {
155 | printf("exit code -1");
156 | return -1;
157 | }
158 | char path[PATH_MAX];
159 | for (int i = ++index; i < argc; ++i) {
160 | memset(path, 0, PATH_MAX);
161 | if (!CreateDir(argv[i])) {
162 | return -1;
163 | }
164 | const char *name = basename(argv[i + 1]);
165 | strcat(path, argv[i]);
166 | strcat(path, "/");
167 | strcat(path, name);
168 | if (access(argv[i + 1], R_OK)) {
169 | if (chmod(argv[i + 1], 00755)) {
170 | LOGE("set file chmod error: %s", argv[i + 1]);
171 | return -2;
172 | }
173 | }
174 | LOGD("copy file %s -> %s", argv[i + 1], path);
175 | if (!CopyFile(path, argv[++i])) {
176 | printf("exit code -2");
177 | return -2;
178 | }
179 | if (chmod(path, lib ? 00755 : 00644)) {
180 | LOGE("set file chmod error: %s", path);
181 | printf("exit code -3");
182 | return -3;
183 | }
184 | if (chown(path, set_uid, set_gid)) {
185 | LOGE("set file owner error: %s", path);
186 | printf("exit code -4");
187 | return -4;
188 | }
189 | if (SetFileXattr(path, lib ? lib_xattr : file_xattr) != 0) {
190 | LOGE("set file xattr failed, file: %s", path);
191 | printf("exit code -5");
192 | return -5;
193 | }
194 | }
195 | return 0;
196 | }
197 |
--------------------------------------------------------------------------------
/library/src/main/cpp/installer/hook_installer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/11/8.
3 | //
4 | #pragma once
5 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/art/art_symbol.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "../linker_globals.h"
4 |
5 | size_t art::DamagedRuntime::jvm_offset_ = -1;
6 | namespace fakelinker {
7 |
8 | ArtSymbol *ArtSymbol::Get() {
9 | static ArtSymbol art;
10 | return &art;
11 | }
12 |
13 | bool ArtSymbol::Init(JNIEnv *env) {
14 | ArtSymbol *art = Get();
15 | if (art->init_) {
16 | return true;
17 | }
18 | auto ext = art::JNIEnvExt::FromJNIEnv(env);
19 | bool init_runtime = art::DamagedRuntime::InitJavaVMOffset(ext->GetVm()->GetRuntime(), ext->GetVm());
20 | auto soinfo = ProxyLinker::Get().FindSoinfoByName("libart.so");
21 | if (!soinfo) {
22 | return false;
23 | }
24 | // art::ArtMethod::PrettyMethod(art::ArtMethod*, bool)
25 | auto pretty_method = soinfo->find_export_symbol_address("_ZN3art9ArtMethod12PrettyMethodEPS0_b");
26 | void *pretty_field = nullptr;
27 | if (pretty_method) {
28 | pretty_field = soinfo->find_export_symbol_address("_ZN3art8ArtField11PrettyFieldEPS0_b");
29 | art->DecodeMethodIdPtr = reinterpret_cast(
30 | soinfo->find_export_symbol_address("_ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID"));
31 | art->DecodeFieldIdPtr = reinterpret_cast(
32 | soinfo->find_export_symbol_address("_ZN3art3jni12JniIdManager13DecodeFieldIdEP9_jfieldID"));
33 | if (init_runtime) {
34 | art->jni_id_manager = art::DamagedRuntime::FromRuntime(ext->GetVm()->GetRuntime())->GetJniIdManager();
35 | }
36 | } else {
37 | pretty_method = soinfo->find_export_symbol_address("_ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb");
38 | pretty_field = soinfo->find_export_symbol_address("_ZN3art11PrettyFieldEPNS_6mirror8ArtFieldEb");
39 | }
40 | art->NterpGetShortyPtr =
41 | reinterpret_cast(soinfo->find_export_symbol_address("NterpGetShorty"));
42 |
43 | if (!art->NterpGetShortyPtr) {
44 | art->ArtMethodGetShortyPtr = reinterpret_cast(
45 | soinfo->find_export_symbol_address("_ZN3art6mirror9ArtMethod9GetShortyEPj"));
46 | }
47 |
48 | art->ArtMethodPrettyMethodPtr = reinterpret_cast(pretty_method);
49 | art->ArtFieldPrettyFieldPtr = reinterpret_cast(pretty_field);
50 | if (art->ArtFieldPrettyFieldPtr != nullptr &&
51 | (android_api < __ANDROID_API_R__ || (art->DecodeFieldIdPtr != nullptr && art->jni_id_manager != nullptr))) {
52 | art->can_pretty_field = true;
53 | }
54 | if (art->ArtMethodPrettyMethodPtr &&
55 | (android_api < __ANDROID_API_R__ || (art->DecodeMethodIdPtr != nullptr && art->jni_id_manager != nullptr))) {
56 | art->can_pretty_method = true;
57 | }
58 | LOGD("art::ArtMethod::PrettyMethod address: %p, art::ArtField::PrettyField address: %p, "
59 | "art::jni::JniIdManager::DecodeMethodId address: %p, art::jni::JniIdManager::DecodeFieldId address: %p, "
60 | "art::jni::JniIdManager address: %p",
61 | art->ArtMethodPrettyMethodPtr, art->ArtFieldPrettyFieldPtr, art->DecodeFieldIdPtr, art->DecodeMethodIdPtr,
62 | art->jni_id_manager);
63 | LOGD("NterpGetShorty address: %p, ArtMethodGetShorty address: %p", art->NterpGetShortyPtr,
64 | art->ArtMethodGetShortyPtr);
65 | art->init_ = true;
66 | return true;
67 | }
68 |
69 | std::string ArtSymbol::PrettyMethod(jmethodID method, bool with_signature) {
70 | if (!can_pretty_method) {
71 | return "";
72 | }
73 | return ArtMethodPrettyMethodPtr(DecodeMethodId(method), with_signature);
74 | }
75 | std::string ArtSymbol::PrettyField(jfieldID field, bool with_signature) {
76 | if (!can_pretty_field) {
77 | return "";
78 | }
79 | return ArtFieldPrettyFieldPtr(DecodeFieldId(field), with_signature);
80 | }
81 |
82 | void *ArtSymbol::DecodeMethodId(jmethodID method) {
83 | if (can_pretty_method) {
84 | return DecodeMethodIdPtr ? DecodeMethodIdPtr(jni_id_manager, method) : method;
85 | }
86 | return nullptr;
87 | }
88 |
89 | void *ArtSymbol::DecodeFieldId(jfieldID field) {
90 | if (can_pretty_field) {
91 | return DecodeFieldIdPtr ? DecodeFieldIdPtr(jni_id_manager, field) : field;
92 | }
93 | return nullptr;
94 | }
95 |
96 | std::string ArtSymbol::GetMethodShorty(/* ArtMethod* */ void *art_method) {
97 | const char *result = nullptr;
98 | if (art_method) {
99 | if (NterpGetShortyPtr) {
100 | result = NterpGetShortyPtr(art_method);
101 | } else if (ArtMethodGetShortyPtr) {
102 | uint32_t out;
103 | result = ArtMethodGetShortyPtr(art_method, &out);
104 | }
105 | }
106 | return result ? result : "";
107 | }
108 |
109 | std::string ArtSymbol::GetMethodShorty(jmethodID method) {
110 | void *art_method = DecodeMethodId(method);
111 | return GetMethodShorty(art_method);
112 | }
113 |
114 |
115 | } // namespace fakelinker
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/art/hook_jni_native_interface_impl.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/12/18.
3 | //
4 |
5 | #pragma once
6 | #include
7 |
8 | #include
9 |
10 | namespace fakelinker {
11 | /**
12 | * @brief Hook Java JNI Native Interface
13 | *
14 | * @param function_offset Methods correspond to offsets in JNINativeInterface
15 | * @param hook_method Hooked function address
16 | * @param backup_method Backup function out address
17 | * @return FakeLinkerError Return hook error code
18 | */
19 | FakeLinkerError HookJniNativeInterface(int function_offset, void *hook_method, void **backup_method);
20 |
21 | int HookJniNativeInterfaces(HookJniUnit *items, int len);
22 |
23 | int HookJavaNativeFunctions(JNIEnv *env, jclass clazz, HookRegisterNativeUnit *items, size_t len);
24 |
25 | bool InitJniFunctionOffset(JNIEnv *env, jclass clazz, jmethodID methodId, void *native, uint32_t flags,
26 | uint32_t unmask);
27 |
28 | bool DefaultInitJniFunctionOffset(JNIEnv *env);
29 |
30 | /**
31 | * @brief Read the native function pointer directly from the ArtMethod structure
32 | *
33 | * @param env JNIEnv pointer, find ArtMethod use
34 | * @param clazz The class where the method being searched is located
35 | * @param methodId The method id being searched
36 | * @return void* Return -1 if the native pointer offset initialization fails,
37 | * -2 if the art method is not found,
38 | * other values are function pointers
39 | */
40 | void *ReadNativeFunction(JNIEnv *env, jclass clazz, jmethodID methodId);
41 |
42 | /* ArtMethod* */ void *ToArtMethod(JNIEnv *env, jmethodID methodId, jclass clazz);
43 | } // namespace fakelinker
44 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/bionic/get_tls.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/12/25.
3 | //
4 |
5 | #pragma once
6 |
7 | #if defined(__aarch64__)
8 | #define __get_tls() \
9 | ({ \
10 | void **__val; \
11 | __asm__("mrs %0, tpidr_el0" : "=r"(__val)); \
12 | __val; \
13 | })
14 | #elif defined(__arm__)
15 | #define __get_tls() \
16 | ({ \
17 | void **__val; \
18 | __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); \
19 | __val; \
20 | })
21 | #elif defined(__i386__)
22 | #define __get_tls() \
23 | ({ \
24 | void **__val; \
25 | __asm__("movl %%gs:0, %0" : "=r"(__val)); \
26 | __val; \
27 | })
28 | #elif defined(__x86_64__)
29 | #define __get_tls() \
30 | ({ \
31 | void **__val; \
32 | __asm__("mov %%fs:0, %0" : "=r"(__val)); \
33 | __val; \
34 | })
35 | #else
36 | #error unsupported architecture
37 | #endif
38 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_block_allocator.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/11/9.
3 | //
4 |
5 | #include "linker_block_allocator.h"
6 |
7 | #include
8 | #include
9 |
10 | #include
11 | #include
12 |
13 | #include
14 |
15 | static constexpr size_t kAllocateSize100 = 4096 * 100;
16 | static constexpr size_t kAllocateSize = 4096;
17 | static constexpr size_t kAllocateSize96 = 65536 * 6;
18 |
19 | struct LinkerBlockAllocatorPage {
20 | LinkerBlockAllocatorPage *next;
21 | uint8_t bytes[kAllocateSize100 - 16] __attribute__((aligned(16)));
22 | };
23 |
24 | struct FreeBlockInfo {
25 | void *next_block;
26 | size_t num_free_blocks;
27 | };
28 |
29 | static size_t get_block_alloca_size() {
30 | if (android_api >= __ANDROID_API_U__) {
31 | return kAllocateSize96;
32 | }
33 | if (android_api >= __ANDROID_API_Q__) {
34 | return kAllocateSize100;
35 | }
36 | return kAllocateSize;
37 | }
38 |
39 | static size_t sizeof_block_alloca_page() {
40 | return android_api >= __ANDROID_API_Q__ ? sizeof(LinkerBlockAllocatorPage) : kAllocateSize;
41 | }
42 |
43 | // the align should be power of 2
44 | static constexpr size_t round_up(size_t size, size_t align) { return (size + (align - 1)) & ~(align - 1); }
45 |
46 | static constexpr size_t kBlockSizeMin = sizeof(FreeBlockInfo);
47 | static constexpr size_t kBlockSizeAlign = sizeof(void *);
48 |
49 | LinkerBlockAllocator::LinkerBlockAllocator(size_t block_size) :
50 | block_size_(round_up(block_size < kBlockSizeMin ? kBlockSizeMin : block_size, 16)), page_list_(nullptr),
51 | free_block_list_(nullptr) {
52 | if (android_api >= __ANDROID_API_Q__) {
53 | allocated_ = 0;
54 | }
55 | }
56 |
57 | void *LinkerBlockAllocator::alloc() {
58 | protect_all(PROT_READ | PROT_WRITE);
59 | if (free_block_list_ == nullptr) {
60 | create_new_page();
61 | }
62 |
63 | auto *block_info = reinterpret_cast(free_block_list_);
64 | if (block_info->num_free_blocks > 1) {
65 | auto *next_block_info = reinterpret_cast(reinterpret_cast(free_block_list_) + block_size_);
66 | next_block_info->next_block = block_info->next_block;
67 | next_block_info->num_free_blocks = block_info->num_free_blocks - 1;
68 | free_block_list_ = next_block_info;
69 | } else {
70 | free_block_list_ = block_info->next_block;
71 | }
72 |
73 | memset(block_info, 0, block_size_);
74 | if (android_api >= __ANDROID_API_Q__) {
75 | ++allocated_;
76 | }
77 | return block_info;
78 | }
79 |
80 | void LinkerBlockAllocator::free(void *block) {
81 | if (block == nullptr) {
82 | return;
83 | }
84 | protect_all(PROT_READ | PROT_WRITE);
85 | LinkerBlockAllocatorPage *page = find_page(block);
86 | ssize_t offset = reinterpret_cast(block) - page->bytes;
87 | if (offset % block_size_ != 0) {
88 | LOGW("The current page has a memory block that cannot be released: %p, "
89 | "offset: %zx, May cause memory leaks.",
90 | page, offset);
91 | // abort();
92 | return;
93 | }
94 |
95 | memset(block, 0, block_size_);
96 |
97 | auto *block_info = reinterpret_cast(block);
98 |
99 | block_info->next_block = free_block_list_;
100 | block_info->num_free_blocks = 1;
101 |
102 | free_block_list_ = block_info;
103 | if (android_api >= __ANDROID_API_Q__) {
104 | --allocated_;
105 | }
106 | }
107 |
108 | void LinkerBlockAllocator::protect_all(int prot) {
109 | for (LinkerBlockAllocatorPage *page = page_list_; page != nullptr; page = page->next) {
110 | if (mprotect(page, get_block_alloca_size(), prot) == -1) {
111 | abort();
112 | }
113 | }
114 | }
115 |
116 | void LinkerBlockAllocator::create_new_page() {
117 | auto *page = reinterpret_cast(
118 | mmap(nullptr, get_block_alloca_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
119 | if (page == MAP_FAILED) {
120 | abort(); // oom
121 | }
122 | prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, get_block_alloca_size(), "linker_alloc");
123 | auto *first_block = reinterpret_cast(page->bytes);
124 | first_block->next_block = free_block_list_;
125 | first_block->num_free_blocks = (get_block_alloca_size() - 16) / block_size_;
126 | free_block_list_ = first_block;
127 | page->next = page_list_;
128 | page_list_ = page;
129 | }
130 |
131 | LinkerBlockAllocatorPage *LinkerBlockAllocator::find_page(void *block) {
132 | if (block == nullptr) {
133 | abort();
134 | }
135 | LinkerBlockAllocatorPage *page = page_list_;
136 | while (page != nullptr) {
137 | const auto *page_ptr = reinterpret_cast(page);
138 | if (block >= (page_ptr + sizeof(page->next)) && block < (page_ptr + get_block_alloca_size())) {
139 | return page;
140 | }
141 | page = page->next;
142 | }
143 | abort();
144 | }
145 |
146 | void LinkerBlockAllocator::purge() {
147 | if (android_api >= __ANDROID_API_Q__ && allocated_) {
148 | return;
149 | }
150 | LinkerBlockAllocatorPage *page = page_list_;
151 | while (page) {
152 | LinkerBlockAllocatorPage *next = page->next;
153 | munmap(page, get_block_alloca_size());
154 | page = next;
155 | }
156 | page_list_ = nullptr;
157 | free_block_list_ = nullptr;
158 | }
159 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_block_allocator.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/11/9.
3 | //
4 | #pragma once
5 |
6 | #include
7 | #include
8 |
9 |
10 | struct LinkerBlockAllocatorPage;
11 |
12 | /*
13 | * https://cs.android.com/android/platform/superproject/+/master:bionic/linker/linker_block_allocator.h
14 | * */
15 | class LinkerBlockAllocator {
16 | public:
17 | explicit LinkerBlockAllocator(size_t block_size);
18 |
19 | void *alloc();
20 |
21 | void free(void *block);
22 |
23 | void protect_all(int prot);
24 |
25 | // Purge all pages if all previously allocated blocks have been freed.
26 | void purge();
27 |
28 | private:
29 | void create_new_page();
30 | LinkerBlockAllocatorPage *find_page(void *block);
31 |
32 | size_t block_size_;
33 | LinkerBlockAllocatorPage *page_list_;
34 | void *free_block_list_;
35 | ANDROID_GE_Q size_t allocated_;
36 | DISALLOW_COPY_AND_ASSIGN(LinkerBlockAllocator);
37 | };
38 |
39 | template
40 | class LinkerTypeAllocator {
41 | public:
42 | LinkerTypeAllocator() : block_allocator_(sizeof(T)) {}
43 |
44 | T *alloc() { return reinterpret_cast(block_allocator_.alloc()); }
45 |
46 | void free(T *t) { block_allocator_.free(t); }
47 |
48 | void protect_all(int prot) { block_allocator_.protect_all(prot); }
49 |
50 | private:
51 | LinkerBlockAllocator block_allocator_;
52 | DISALLOW_COPY_AND_ASSIGN(LinkerTypeAllocator);
53 | };
54 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_common_types.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/11/9.
3 | //
4 |
5 | #include "linker_common_types.h"
6 |
7 | #include
8 |
9 | #include "linker_symbol.h"
10 |
11 |
12 | LinkedListEntry *SoinfoListAllocator::alloc() {
13 | return fakelinker::linker_symbol.g_soinfo_links_allocator.Get()->alloc();
14 | }
15 |
16 | void SoinfoListAllocator::free(LinkedListEntry *entry) {
17 | fakelinker::linker_symbol.g_soinfo_links_allocator.Get()->free(entry);
18 | }
19 |
20 | LinkedListEntry *SoinfoTListAllocator::alloc() {
21 | return reinterpret_cast *>(
22 | fakelinker::linker_symbol.g_soinfo_links_allocator.Get()->alloc());
23 | }
24 |
25 | void SoinfoTListAllocator::free(LinkedListEntry *entry) {
26 | fakelinker::linker_symbol.g_soinfo_links_allocator.Get()->free(reinterpret_cast *>(entry));
27 | }
28 |
29 | ANDROID_GE_N LinkedListEntry *NamespaceListAllocator::alloc() {
30 | return fakelinker::linker_symbol.g_namespace_list_allocator.Get()->alloc();
31 | }
32 |
33 | ANDROID_GE_N void NamespaceListAllocator::free(LinkedListEntry *entry) {
34 | fakelinker::linker_symbol.g_namespace_list_allocator.Get()->free(entry);
35 | }
36 |
37 | static void LinkerBlockProtectAll(int port) {
38 | // 由于我们修改的同时linker可能也在同时修改,因此只保护读写,不保护读
39 | if ((port & PROT_WRITE) == 0) {
40 | return;
41 | }
42 | fakelinker::linker_symbol.g_soinfo_allocator.Get()->protect_all(port);
43 | fakelinker::linker_symbol.g_soinfo_links_allocator.Get()->protect_all(port);
44 | if (android_api >= __ANDROID_API_N__) {
45 | fakelinker::linker_symbol.g_namespace_allocator.Get()->protect_all(port);
46 | fakelinker::linker_symbol.g_namespace_list_allocator.Get()->protect_all(port);
47 | }
48 | }
49 |
50 | LinkerBlockLock::LinkerBlockLock() {
51 | ref_count_++;
52 | LinkerBlockProtectAll(PROT_READ | PROT_WRITE);
53 | }
54 |
55 | LinkerBlockLock::~LinkerBlockLock() {
56 | if (--ref_count_ == 0) {
57 | LinkerBlockProtectAll(PROT_READ);
58 | }
59 | }
60 |
61 | size_t LinkerBlockLock::ref_count_ = 0;
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_common_types.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 |
7 | #include "linked_list.h"
8 | #include "linker_block_allocator.h"
9 |
10 | struct soinfo;
11 | struct soinfoT;
12 | struct android_namespace_t;
13 |
14 | class SoinfoListAllocator {
15 | public:
16 | static LinkedListEntry *alloc();
17 |
18 | static void free(LinkedListEntry *entry);
19 |
20 | private:
21 | DISALLOW_IMPLICIT_CONSTRUCTORS(SoinfoListAllocator);
22 | };
23 |
24 | class SoinfoTListAllocator {
25 | public:
26 | static LinkedListEntry *alloc();
27 |
28 | static void free(LinkedListEntry *entry);
29 |
30 | private:
31 | DISALLOW_IMPLICIT_CONSTRUCTORS(SoinfoTListAllocator);
32 | };
33 |
34 |
35 | ANDROID_GE_N class NamespaceListAllocator {
36 | public:
37 | ANDROID_GE_N static LinkedListEntry *alloc();
38 |
39 | ANDROID_GE_N static void free(LinkedListEntry *entry);
40 |
41 | private:
42 | DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceListAllocator);
43 | };
44 |
45 | template
46 | class SizeBasedAllocator {
47 | public:
48 | static void *alloc() { return allocator_.alloc(); }
49 |
50 | static void free(void *ptr) { allocator_.free(ptr); }
51 |
52 | static void purge() { allocator_.purge(); }
53 |
54 | private:
55 | static LinkerBlockAllocator allocator_;
56 | };
57 |
58 | template
59 | class TypeBasedAllocator {
60 | public:
61 | static T *alloc() { return reinterpret_cast(SizeBasedAllocator::alloc()); }
62 |
63 | static void free(T *ptr) { SizeBasedAllocator::free(ptr); }
64 |
65 | static void purge() { SizeBasedAllocator::purge(); }
66 | };
67 |
68 | template
69 | LinkerBlockAllocator SizeBasedAllocator::allocator_(size);
70 |
71 | typedef LinkedList soinfo_list_t;
72 | typedef LinkedListT soinfo_list_t_T;
73 | typedef LinkedListWrapper soinfo_list_t_wrapper;
74 |
75 | typedef LinkedList android_namespace_list_t;
76 | typedef LinkedListT android_namespace_list_t_T;
77 | typedef LinkedListWrapper android_namespace_list_t_wrapper;
78 |
79 | template
80 | using linked_list_t = LinkedList>>;
81 |
82 | template
83 | using linked_list_t_T = LinkedListT>>;
84 |
85 | template
86 | using linked_list_t_wrapper = LinkedListWrapper>>;
87 |
88 | typedef linked_list_t SoinfoLinkedList;
89 | typedef linked_list_t_T SoinfoLinkedListT;
90 | typedef linked_list_t_wrapper SoinfoLinkedListWrapper;
91 |
92 | class LinkerBlockLock {
93 |
94 | public:
95 | LinkerBlockLock();
96 |
97 | ~LinkerBlockLock();
98 |
99 | private:
100 | static size_t ref_count_;
101 | };
102 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_dynamic.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2024/5/25.
3 | //
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | C_API JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
11 | JNIEnv *env;
12 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) {
13 | async_safe_fatal("JNI environment error");
14 | }
15 | jint code = init_fakelinker(env,
16 | static_cast(FakeLinkerMode::kFMSoinfo | FakeLinkerMode::kFMNativeHook |
17 | FakeLinkerMode::kFMJavaRegister),
18 | nullptr);
19 | if (code != 0) {
20 | LOGE("init fakelinker result: %d", code);
21 | }
22 | return JNI_VERSION_1_6;
23 | }
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_globals.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/11/5.
3 | //
4 | #pragma once
5 |
6 | #include
7 | #include
8 |
9 | #include "linker_namespaces.h"
10 | #include "linker_soinfo.h"
11 |
12 | namespace fakelinker {
13 | class ProxyLinker {
14 | public:
15 | static ProxyLinker &Get();
16 |
17 | static void *CallDlopen(const char *filename, int flags, void *caller_addr, const android_dlextinfo *extinfo);
18 |
19 | static void *CallDlsym(void *handle, const char *symbol, void *caller_addr, const char *version);
20 |
21 | ANDROID_GE_N soinfo *SoinfoFromHandle(const void *handle);
22 |
23 | ANDROID_GE_N std::vector GetAllNamespace(bool flush);
24 |
25 | ANDROID_GE_N android_namespace_t *FindNamespaceByName(const char *name);
26 |
27 | ANDROID_GE_N static android_namespace_t *GetDefaultNamespace();
28 |
29 | ANDROID_GE_N static void *GetNamespaceCallerAddress(android_namespace_t *np);
30 | /*
31 | * 改变soinfo的命名空间,若np为null则添加到默认命名空间
32 | * */
33 | ANDROID_GE_N void ChangeSoinfoOfNamespace(soinfo *so, android_namespace_t *np);
34 |
35 | ANDROID_GE_N bool AddGlobalSoinfoToNamespace(soinfo *global, android_namespace_t *np);
36 |
37 | ANDROID_GE_N bool RemoveSoinfoFromNamespace(soinfo *so, android_namespace_t *np, bool clear_global_flags);
38 |
39 | ANDROID_GE_N void AddSoinfoToDefaultNamespace(soinfo *si);
40 |
41 | ANDROID_GE_N void *CallDoDlopenN(const char *filename, int flags, const android_dlextinfo *extinfo,
42 | void *caller_addr);
43 |
44 | ANDROID_GE_N bool CallDoDlsymN(void *handle, const char *symbol, const char *version, void *caller_addr, void **sym);
45 |
46 | ANDROID_GE_N android_namespace_t *CallCreateNamespace(const char *name, const char *ld_library_path,
47 | const char *default_library_path, uint64_t type,
48 | const char *permitted_when_isolated_path,
49 | android_namespace_t *parent_namespace, const void *caller_addr);
50 |
51 | ANDROID_LE_M void *CallDoDlopen(const char *name, int flags, const android_dlextinfo *extinfo);
52 |
53 | ANDROID_LE_M void *CallDoDlsym(void *handle, const char *symbol);
54 |
55 | /*
56 | * 当dlopen,dlsym失败时需要设置错误,否者后续调用dlerror而未判断字符串为null时导致错误
57 | * */
58 | void FormatDlerror(const char *msg, const char *detail);
59 |
60 | void **GetTls();
61 |
62 | soinfo *FindSoinfoByName(const char *name);
63 |
64 | soinfo *FindSoinfoByNameInNamespace(const char *name, android_namespace_t *np);
65 |
66 | soinfo *FindSoinfoByPath(const char *path);
67 |
68 | std::vector GetAllSoinfo();
69 |
70 | soinfo *FindContainingLibrary(const void *p);
71 |
72 | /*
73 | * linker对应的soinfo结构体,经常使用备份一份
74 | * */
75 | soinfo *GetLinkerSoinfo();
76 |
77 | /*
78 | * 使用dlsym查找符号,只能查找STB_GLOBAL | STB_WEAK 导出的符号
79 | * dlsym查找符号如果自己没查找出来还会继续查找依赖so
80 | *
81 | * local_group_root
82 | * 1. Android 7.0+ 自身soinfo排在第一,然后是依赖so
83 | *
84 | * dlsym(RTLD_NEXT)行为解析
85 | * 1. Android 7.0+ 从调用者所在命名空间的当前 soinfo 的下一个开始查找有
86 | * RTLD_GLOBAL 标签的库, 如果没有找到则会继续判断条件然后查找
87 | * local_group_root,但是都会排除 caller自身
88 | * * Android 9.0+ 则直接从caller local_group_root 开始查找
89 | * * Android 7.0 ~ Android 8.1 判断caller库没有 RTLD_GLOBAL 才查找
90 | *
91 | * local_group_root
92 | * 2. Android 7.0以下 没有命名空间,此时 soinfo是一条链表,从caller
93 | * soinfo->next开始查找有 RTLD_GLOBAL 标签的库, 如果没有找到则判断caller库没有
94 | * RTLD_GLOBAL 才查找 local_group_root
95 | *
96 | * dlsym(RTLD_DEFAULT)行为解析
97 | * 1. Android 7.0及以上 从调用者所在命名空间的第一个soinfo开始查找有
98 | * RTLD_GLOBAL 标签的库, 如果没找到再同 RTLD_NEXT 一样判断条件从caller
99 | * local_group_root 开始查找, RTLD_DEFAULT 并不排除caller自身
100 | * 2. Android 7.0以下从第一个 soinfo 开始查找有 RTLD_GLOBAL
101 | * 标签的库,如果没有找到再继续判断条件从caller local_group_root 开始查找
102 | * */
103 | void *FindSymbolByDlsym(soinfo *si, const char *name);
104 |
105 | void AddSoinfoToGlobal(soinfo *si);
106 |
107 | bool RemoveGlobalSoinfo(soinfo *si);
108 |
109 | bool IsGlobalSoinfo(soinfo *si);
110 |
111 | int *GetGLdDebugVerbosity();
112 | bool SetLdDebugVerbosity(int level);
113 |
114 | bool ManualRelinkLibrary(soinfo *global, soinfo *child);
115 |
116 | bool ManualRelinkLibrary(soinfo *global, soinfo *child, std::vector &filters);
117 |
118 | bool ManualRelinkLibrary(symbol_relocations &rels, soinfo *child);
119 |
120 | bool ManualRelinkLibraries(soinfo *global, const std::vector &sonames,
121 | const std::vector &filters);
122 |
123 | bool ManualRelinkLibraries(soinfo *global, int len, const std::vector &targets,
124 | std::vector &filters);
125 |
126 | bool SystemRelinkLibrary(soinfo *so);
127 |
128 | bool SystemRelinkLibraries(const std::vector &sonames);
129 |
130 | soinfo_list_t GetSoinfoGlobalGroup(soinfo *root);
131 |
132 | private:
133 | ANDROID_LE_M soinfo_list_t GetGlobalGroupM();
134 |
135 | ANDROID_GE_M bool RelinkSoinfoImplM(soinfo *si);
136 |
137 | ANDROID_LE_L1 bool RelinkSoinfoImplL(soinfo *si);
138 |
139 | private:
140 | ANDROID_GE_N std::vector namespaces;
141 | };
142 | } // namespace fakelinker
143 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_gnu_hash_neon.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 The Android Open Source Project
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in
12 | * the documentation and/or other materials provided with the
13 | * distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | * SUCH DAMAGE.
27 | */
28 |
29 | #pragma once
30 |
31 | #include
32 |
33 | #include
34 |
35 | std::pair calculate_gnu_hash_neon(const char *name);
36 |
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_mapped_file_fragment.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2022/5/26.
3 | //
4 |
5 | #include "fakelinker/linker_mapped_file_fragment.h"
6 |
7 | #include
8 |
9 | #include "linker_util.h"
10 |
11 | MappedFileFragment::MappedFileFragment() : map_start_(nullptr), map_size_(0), data_(nullptr), size_(0) {}
12 |
13 | MappedFileFragment::~MappedFileFragment() {
14 | if (map_start_ != nullptr) {
15 | munmap(map_start_, map_size_);
16 | }
17 | }
18 |
19 | bool MappedFileFragment::Map(int fd, off64_t base_offset, size_t elf_offset, size_t size) {
20 | off64_t offset;
21 | if (!safe_add(&offset, base_offset, elf_offset)) {
22 | return false;
23 | }
24 |
25 | off64_t page_min = page_start(offset);
26 | off64_t end_offset;
27 |
28 | if (!safe_add(&end_offset, offset, size)) {
29 | return false;
30 | }
31 | if (!safe_add(&end_offset, end_offset, page_offset(offset))) {
32 | return false;
33 | }
34 |
35 | size_t map_size = static_cast(end_offset - page_min);
36 | if (!(map_size >= size)) {
37 | return false;
38 | }
39 |
40 | uint8_t *map_start = static_cast(mmap64(nullptr, map_size, PROT_READ, MAP_PRIVATE, fd, page_min));
41 |
42 | if (map_start == MAP_FAILED) {
43 | return false;
44 | }
45 |
46 | map_start_ = map_start;
47 | map_size_ = map_size;
48 |
49 | data_ = map_start + page_offset(offset);
50 | size_ = size;
51 |
52 | return true;
53 | }
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_relocate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 |
7 | #include "linker_sleb128.h"
8 | #include "linker_soinfo.h"
9 |
10 |
11 | static constexpr ElfW(Versym) kVersymHiddenBit = 0x8000;
12 |
13 | enum RelocationKind { kRelocAbsolute = 0, kRelocRelative, kRelocSymbol, kRelocSymbolCached, kRelocMax };
14 |
15 | void count_relocation(RelocationKind kind);
16 |
17 | template
18 | void count_relocation_if(RelocationKind kind) {
19 | if (Enabled) {
20 | count_relocation(kind);
21 | }
22 | }
23 |
24 | inline bool is_symbol_global_and_defined(soinfo *si, const ElfW(Sym) * s) {
25 | if (__predict_true(ELF_ST_BIND(s->st_info) == STB_GLOBAL || ELF_ST_BIND(s->st_info) == STB_WEAK)) {
26 | return s->st_shndx != SHN_UNDEF;
27 | } else if (__predict_false(ELF_ST_BIND(s->st_info) != STB_LOCAL)) {
28 | LOGW("Warning: unexpected ST_BIND value: %d for \"%s\" in \"%s\" (ignoring)", ELF_ST_BIND(s->st_info),
29 | si->get_string(s->st_name), si->realpath());
30 | }
31 | return false;
32 | }
33 |
34 | const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1;
35 | const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
36 | const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
37 | const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
38 |
39 | template
40 | inline bool for_all_packed_relocs(sleb128_decoder decoder, F &&callback) {
41 | const size_t num_relocs = decoder.pop_front();
42 |
43 | rel_t reloc = {
44 | .r_offset = decoder.pop_front(),
45 | };
46 |
47 | for (size_t idx = 0; idx < num_relocs;) {
48 | const size_t group_size = decoder.pop_front();
49 | const size_t group_flags = decoder.pop_front();
50 |
51 | size_t group_r_offset_delta = 0;
52 |
53 | if (group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) {
54 | group_r_offset_delta = decoder.pop_front();
55 | }
56 | if (group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) {
57 | reloc.r_info = decoder.pop_front();
58 | }
59 |
60 | #if defined(USE_RELA)
61 | const size_t group_flags_reloc =
62 | group_flags & (RELOCATION_GROUP_HAS_ADDEND_FLAG | RELOCATION_GROUPED_BY_ADDEND_FLAG);
63 | if (group_flags_reloc == RELOCATION_GROUP_HAS_ADDEND_FLAG) {
64 | // Each relocation has an addend. This is the default situation with lld's current encoder.
65 | } else if (group_flags_reloc == (RELOCATION_GROUP_HAS_ADDEND_FLAG | RELOCATION_GROUPED_BY_ADDEND_FLAG)) {
66 | reloc.r_addend += decoder.pop_front();
67 | } else {
68 | reloc.r_addend = 0;
69 | }
70 | #else
71 | if (__predict_false(group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG)) {
72 | // This platform does not support rela, and yet we have it encoded in android_rel section.
73 | async_safe_fatal("unexpected r_addend in android.rel section");
74 | }
75 | #endif
76 |
77 | for (size_t i = 0; i < group_size; ++i) {
78 | if (group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) {
79 | reloc.r_offset += group_r_offset_delta;
80 | } else {
81 | reloc.r_offset += decoder.pop_front();
82 | }
83 | if ((group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) == 0) {
84 | reloc.r_info = decoder.pop_front();
85 | }
86 | #if defined(USE_RELA)
87 | if (group_flags_reloc == RELOCATION_GROUP_HAS_ADDEND_FLAG) {
88 | reloc.r_addend += decoder.pop_front();
89 | }
90 | #endif
91 | if (!callback(reloc)) {
92 | return false;
93 | }
94 | }
95 |
96 | idx += group_size;
97 | }
98 |
99 | return true;
100 | }
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_relocs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 The Android Open Source Project
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in
12 | * the documentation and/or other materials provided with the
13 | * distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | * SUCH DAMAGE.
27 | */
28 |
29 | #pragma once
30 |
31 | #include
32 | #include
33 |
34 | #define R_GENERIC_NONE 0 // R_*_NONE is always 0
35 |
36 | #if defined(__aarch64__)
37 |
38 | #define R_GENERIC_JUMP_SLOT R_AARCH64_JUMP_SLOT
39 | // R_AARCH64_ABS64 is classified as a static relocation but it is common in
40 | // DSOs.
41 | #define R_GENERIC_ABSOLUTE R_AARCH64_ABS64
42 | #define R_GENERIC_GLOB_DAT R_AARCH64_GLOB_DAT
43 | #define R_GENERIC_RELATIVE R_AARCH64_RELATIVE
44 | #define R_GENERIC_IRELATIVE R_AARCH64_IRELATIVE
45 | #define R_GENERIC_COPY R_AARCH64_COPY
46 | #define R_GENERIC_TLS_DTPMOD R_AARCH64_TLS_DTPMOD
47 | #define R_GENERIC_TLS_DTPREL R_AARCH64_TLS_DTPREL
48 | #define R_GENERIC_TLS_TPREL R_AARCH64_TLS_TPREL
49 | #define R_GENERIC_TLSDESC R_AARCH64_TLSDESC
50 |
51 | #elif defined(__arm__)
52 |
53 | #define R_GENERIC_JUMP_SLOT R_ARM_JUMP_SLOT
54 | // R_ARM_ABS32 is classified as a static relocation but it is common in DSOs.
55 | #define R_GENERIC_ABSOLUTE R_ARM_ABS32
56 | #define R_GENERIC_GLOB_DAT R_ARM_GLOB_DAT
57 | #define R_GENERIC_RELATIVE R_ARM_RELATIVE
58 | #define R_GENERIC_IRELATIVE R_ARM_IRELATIVE
59 | #define R_GENERIC_COPY R_ARM_COPY
60 | #define R_GENERIC_TLS_DTPMOD R_ARM_TLS_DTPMOD32
61 | #define R_GENERIC_TLS_DTPREL R_ARM_TLS_DTPOFF32
62 | #define R_GENERIC_TLS_TPREL R_ARM_TLS_TPOFF32
63 | #define R_GENERIC_TLSDESC R_ARM_TLS_DESC
64 |
65 | #elif defined(__i386__)
66 |
67 | #define R_GENERIC_JUMP_SLOT R_386_JMP_SLOT
68 | #define R_GENERIC_ABSOLUTE R_386_32
69 | #define R_GENERIC_GLOB_DAT R_386_GLOB_DAT
70 | #define R_GENERIC_RELATIVE R_386_RELATIVE
71 | #define R_GENERIC_IRELATIVE R_386_IRELATIVE
72 | #define R_GENERIC_COPY R_386_COPY
73 | #define R_GENERIC_TLS_DTPMOD R_386_TLS_DTPMOD32
74 | #define R_GENERIC_TLS_DTPREL R_386_TLS_DTPOFF32
75 | #define R_GENERIC_TLS_TPREL R_386_TLS_TPOFF
76 | #define R_GENERIC_TLSDESC R_386_TLS_DESC
77 |
78 | #elif defined(__x86_64__)
79 |
80 | #define R_GENERIC_JUMP_SLOT R_X86_64_JUMP_SLOT
81 | #define R_GENERIC_ABSOLUTE R_X86_64_64
82 | #define R_GENERIC_GLOB_DAT R_X86_64_GLOB_DAT
83 | #define R_GENERIC_RELATIVE R_X86_64_RELATIVE
84 | #define R_GENERIC_IRELATIVE R_X86_64_IRELATIVE
85 | #define R_GENERIC_COPY R_X86_64_COPY
86 | #define R_GENERIC_TLS_DTPMOD R_X86_64_DTPMOD64
87 | #define R_GENERIC_TLS_DTPREL R_X86_64_DTPOFF64
88 | #define R_GENERIC_TLS_TPREL R_X86_64_TPOFF64
89 | #define R_GENERIC_TLSDESC R_X86_64_TLSDESC
90 |
91 | #endif
92 |
93 | inline bool is_tls_reloc(ElfW(Word) type) {
94 | switch (type) {
95 | case R_GENERIC_TLS_DTPMOD:
96 | case R_GENERIC_TLS_DTPREL:
97 | case R_GENERIC_TLS_TPREL:
98 | case R_GENERIC_TLSDESC:
99 | return true;
100 | default:
101 | return false;
102 | }
103 | }
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_sleb128.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 The Android Open Source Project
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in
12 | * the documentation and/or other materials provided with the
13 | * distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | * SUCH DAMAGE.
27 | */
28 |
29 | #pragma once
30 |
31 | #include
32 |
33 | #include
34 |
35 | // Helper classes for decoding LEB128, used in packed relocation data.
36 | // http://en.wikipedia.org/wiki/LEB128
37 |
38 | class sleb128_decoder {
39 | public:
40 | sleb128_decoder(const uint8_t *buffer, size_t count) : current_(buffer), end_(buffer + count) {}
41 |
42 | size_t pop_front() {
43 | size_t value = 0;
44 | static const size_t size = 8 * sizeof(value);
45 |
46 | size_t shift = 0;
47 | uint8_t byte;
48 |
49 | do {
50 | if (current_ >= end_) {
51 | async_safe_fatal("sleb128_decoder ran out of bounds");
52 | }
53 | byte = *current_++;
54 | value |= (static_cast(byte & 127) << shift);
55 | shift += 7;
56 | } while (byte & 128);
57 |
58 | if (shift < size && (byte & 64)) {
59 | value |= -(static_cast(1) << shift);
60 | }
61 |
62 | return value;
63 | }
64 |
65 | private:
66 | const uint8_t *current_;
67 | const uint8_t *const end_;
68 | };
69 |
70 | class uleb128_decoder {
71 | public:
72 | uleb128_decoder(const uint8_t *buffer, size_t count) : current_(buffer), end_(buffer + count) {}
73 |
74 | uint64_t pop_front() {
75 | uint64_t value = 0;
76 |
77 | size_t shift = 0;
78 | uint8_t byte;
79 |
80 | do {
81 | if (current_ >= end_) {
82 | async_safe_fatal("uleb128_decoder ran out of bounds");
83 | }
84 | byte = *current_++;
85 | value |= (static_cast(byte & 127) << shift);
86 | shift += 7;
87 | } while (byte & 128);
88 |
89 | return value;
90 | }
91 |
92 | bool has_bytes() { return current_ < end_; }
93 |
94 | private:
95 | const uint8_t *current_;
96 | const uint8_t *const end_;
97 | };
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_tls.cpp:
--------------------------------------------------------------------------------
1 | #include "linker_tls.h"
2 |
3 | #include
4 |
5 | const TlsModule &get_tls_module(size_t module_id) { async_safe_fatal("unsupport get_tls_module"); }
6 |
7 | size_t tlsdesc_resolver_static(size_t) { async_safe_fatal("unsupport tlsdesc_resolver_static"); }
8 |
9 | size_t tlsdesc_resolver_dynamic(size_t) { async_safe_fatal("unsupport tlsdesc_resolver_dynamic"); }
10 |
11 | size_t tlsdesc_resolver_unresolved_weak(size_t) { async_safe_fatal("unsupport tlsdesc_resolver_unresolved_weak"); }
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_tls.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #if defined(__riscv)
6 | // TLS_DTV_OFFSET is a constant used in relocation fields, defined in RISC-V ELF Specification[1]
7 | // The front of the TCB contains a pointer to the DTV, and each pointer in DTV
8 | // points to 0x800 past the start of a TLS block to make full use of the range
9 | // of load/store instructions, refer to [2].
10 | //
11 | // [1]: RISC-V ELF Specification.
12 | // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#constants
13 | // [2]: Documentation of TLS data structures
14 | // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/53
15 | #define TLS_DTV_OFFSET 0x800
16 | #else
17 | #define TLS_DTV_OFFSET 0
18 | #endif
19 |
20 | struct TlsSegment {
21 | size_t size = 0;
22 | size_t alignment = 1;
23 | const void *init_ptr = ""; // Field is non-null even when init_size is 0.
24 | size_t init_size = 0;
25 | };
26 |
27 | struct soinfo_tls {
28 | TlsSegment segment;
29 | size_t module_id = 0;
30 | };
31 |
32 | static constexpr size_t kTlsGenerationNone = 0;
33 | static constexpr size_t kTlsGenerationFirst = 1;
34 |
35 | // The first ELF TLS module has ID 1. Zero is reserved for the first word of
36 | // the DTV, a generation count. Unresolved weak symbols also use module ID 0.
37 | static constexpr size_t kTlsUninitializedModuleId = 0;
38 |
39 | static inline size_t __tls_module_id_to_idx(size_t id) { return id - 1; }
40 |
41 | static inline size_t __tls_module_idx_to_id(size_t idx) { return idx + 1; }
42 |
43 | // A descriptor for a single ELF TLS module.
44 | struct TlsModule {
45 | TlsSegment segment;
46 |
47 | // Offset into the static TLS block or SIZE_MAX for a dynamic module.
48 | size_t static_offset = SIZE_MAX;
49 |
50 | // The generation in which this module was loaded. Dynamic TLS lookups use
51 | // this field to detect when a module has been unloaded.
52 | size_t first_generation = kTlsGenerationNone;
53 |
54 | // Used by the dynamic linker to track the associated soinfo* object.
55 | void *soinfo_ptr = nullptr;
56 | };
57 | struct soinfo;
58 |
59 | void linker_setup_exe_static_tls(const char *progname);
60 | void linker_finalize_static_tls();
61 |
62 | void register_soinfo_tls(soinfo *si);
63 | void unregister_soinfo_tls(soinfo *si);
64 |
65 | const TlsModule &get_tls_module(size_t module_id);
66 |
67 | typedef size_t TlsDescResolverFunc(size_t);
68 |
69 | struct TlsIndex {
70 | size_t module_id;
71 | size_t offset;
72 | };
73 |
74 | struct TlsDescriptor {
75 | #if defined(__arm__)
76 | size_t arg;
77 | TlsDescResolverFunc *func;
78 | #else
79 | TlsDescResolverFunc *func;
80 | size_t arg;
81 | #endif
82 | };
83 |
84 | struct TlsDynamicResolverArg {
85 | size_t generation;
86 | TlsIndex index;
87 | };
88 |
89 | size_t tlsdesc_resolver_static(size_t);
90 | size_t tlsdesc_resolver_dynamic(size_t);
91 | size_t tlsdesc_resolver_unresolved_weak(size_t);
--------------------------------------------------------------------------------
/library/src/main/cpp/linker/linker_util.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by beich on 2020/11/8.
3 | //
4 | #pragma once
5 |
6 | #include
7 |
8 | #include