|
38 | 38 | #define XDL_LINKER_SYM_DLOPEN_O "__dl__Z8__dlopenPKciPKv"
|
39 | 39 | #define XDL_LINKER_SYM_LOADER_DLOPEN_P "__loader_dlopen"
|
40 | 40 |
|
| 41 | +#ifndef __LP64__ |
| 42 | +#define LIB "lib" |
| 43 | +#else |
| 44 | +#define LIB "lib64" |
| 45 | +#endif |
| 46 | + |
41 | 47 | typedef void *(*xdl_linker_dlopen_n_t)(const char *, int, const void *, void *);
|
42 | 48 | typedef void *(*xdl_linker_dlopen_o_t)(const char *, int, const void *);
|
43 | 49 |
|
44 | 50 | static pthread_mutex_t *xdl_linker_mutex = NULL;
|
45 | 51 | static void *xdl_linker_dlopen = NULL;
|
46 | 52 |
|
47 |
| -static void *xdl_linker_caller_addr[] = { |
48 |
| - NULL, // default |
49 |
| - NULL, // art |
50 |
| - NULL // vendor |
51 |
| -}; |
52 |
| - |
53 |
| -#ifndef __LP64__ |
54 |
| -#define XDL_LINKER_LIB "lib" |
55 |
| -#else |
56 |
| -#define XDL_LINKER_LIB "lib64" |
57 |
| -#endif |
58 |
| -static const char *xdl_linker_vendor_path[] = { |
59 |
| - // order is important |
60 |
| - "/vendor/" XDL_LINKER_LIB "/egl/", "/vendor/" XDL_LINKER_LIB "/hw/", |
61 |
| - "/vendor/" XDL_LINKER_LIB "/", "/odm/" XDL_LINKER_LIB "/", |
62 |
| - "/vendor/" XDL_LINKER_LIB "/vndk-sp/", "/odm/" XDL_LINKER_LIB "/vndk-sp/"}; |
| 53 | +typedef enum { MATCH_PREFIX, MATCH_SUFFIX } xdl_linker_match_type_t; |
| 54 | + |
| 55 | +#pragma clang diagnostic push |
| 56 | +#pragma clang diagnostic ignored "-Wpadded" |
| 57 | +typedef struct { |
| 58 | + xdl_linker_match_type_t type; |
| 59 | + const char *value; |
| 60 | +} xdl_linker_match_t; |
| 61 | +#pragma clang diagnostic pop |
| 62 | + |
| 63 | +typedef struct { |
| 64 | + void *addr; |
| 65 | + xdl_linker_match_t *matches; |
| 66 | + size_t matches_cursor; |
| 67 | +} xdl_linker_caller_t; |
| 68 | + |
| 69 | +// https://source.android.com/docs/core/architecture/vndk/linker-namespace |
| 70 | +// The following rules are loose and incomplete, you can add more according to your needs. |
| 71 | +static xdl_linker_match_t xdl_linker_match_default[] = {{MATCH_SUFFIX, "/libc.so"}}; |
| 72 | +static xdl_linker_match_t xdl_linker_match_art[] = {{MATCH_SUFFIX, "/libart.so"}}; |
| 73 | +static xdl_linker_match_t xdl_linker_match_sphal[] = {{MATCH_PREFIX, "/vendor/" LIB "/egl/"}, |
| 74 | + {MATCH_PREFIX, "/vendor/" LIB "/hw/"}, |
| 75 | + {MATCH_PREFIX, "/vendor/" LIB "/"}, |
| 76 | + {MATCH_PREFIX, "/odm/" LIB "/"}}; |
| 77 | +static xdl_linker_match_t xdl_linker_match_vndk[] = {{MATCH_PREFIX, "/apex/com.android.vndk.v"}, |
| 78 | + {MATCH_PREFIX, "/vendor/" LIB "/vndk-sp/"}, |
| 79 | + {MATCH_PREFIX, "/odm/" LIB "/vndk-sp/"}}; |
| 80 | +static xdl_linker_caller_t xdl_linker_callers[] = { |
| 81 | + {NULL, xdl_linker_match_default, sizeof(xdl_linker_match_default) / sizeof(xdl_linker_match_t)}, |
| 82 | + {NULL, xdl_linker_match_art, sizeof(xdl_linker_match_art) / sizeof(xdl_linker_match_t)}, |
| 83 | + {NULL, xdl_linker_match_sphal, sizeof(xdl_linker_match_sphal) / sizeof(xdl_linker_match_t)}, |
| 84 | + {NULL, xdl_linker_match_vndk, sizeof(xdl_linker_match_vndk) / sizeof(xdl_linker_match_t)}}; |
63 | 85 |
|
64 | 86 | static void xdl_linker_init_symbols_impl(void) {
|
65 | 87 | // find linker from: /proc/self/maps (API level < 18) or getauxval (API level >= 18)
|
@@ -121,41 +143,44 @@ static void *xdl_linker_get_caller_addr(struct dl_phdr_info *info) {
|
121 | 143 | return NULL;
|
122 | 144 | }
|
123 | 145 |
|
124 |
| -static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) { |
125 |
| - (void)size; |
126 |
| - |
127 |
| - size_t *vendor_match = (size_t *)arg; |
| 146 | +static void xdl_linker_save_caller_addr(struct dl_phdr_info *info, xdl_linker_caller_t *caller, |
| 147 | + size_t cursor) { |
| 148 | + void *addr = xdl_linker_get_caller_addr(info); |
| 149 | + if (NULL != addr) { |
| 150 | + caller->addr = addr; |
| 151 | + caller->matches_cursor = cursor; |
| 152 | + } |
| 153 | +} |
128 | 154 |
|
| 155 | +static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) { |
| 156 | + (void)size, (void)arg; |
129 | 157 | if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue
|
130 | 158 |
|
131 |
| - if (NULL == xdl_linker_caller_addr[0] && xdl_util_ends_with(info->dlpi_name, "/libc.so")) |
132 |
| - xdl_linker_caller_addr[0] = xdl_linker_get_caller_addr(info); |
133 |
| - |
134 |
| - if (NULL == xdl_linker_caller_addr[1] && xdl_util_ends_with(info->dlpi_name, "/libart.so")) |
135 |
| - xdl_linker_caller_addr[1] = xdl_linker_get_caller_addr(info); |
136 |
| - |
137 |
| - if (0 != *vendor_match) { |
138 |
| - for (size_t i = 0; i < *vendor_match; i++) { |
139 |
| - if (xdl_util_starts_with(info->dlpi_name, xdl_linker_vendor_path[i])) { |
140 |
| - void *caller_addr = xdl_linker_get_caller_addr(info); |
141 |
| - if (NULL != caller_addr) { |
142 |
| - xdl_linker_caller_addr[2] = caller_addr; |
143 |
| - *vendor_match = i; |
144 |
| - } |
| 159 | + int ret = 1; // OK |
| 160 | + for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { |
| 161 | + xdl_linker_caller_t *caller = &xdl_linker_callers[i]; |
| 162 | + for (size_t j = 0; j < caller->matches_cursor; j++) { |
| 163 | + xdl_linker_match_t *match = &caller->matches[j]; |
| 164 | + switch (match->type) { |
| 165 | + case MATCH_PREFIX: |
| 166 | + if (xdl_util_starts_with(info->dlpi_name, match->value)) { |
| 167 | + xdl_linker_save_caller_addr(info, caller, j); |
| 168 | + } |
| 169 | + break; |
| 170 | + case MATCH_SUFFIX: |
| 171 | + if (xdl_util_ends_with(info->dlpi_name, match->value)) { |
| 172 | + xdl_linker_save_caller_addr(info, caller, j); |
| 173 | + } |
| 174 | + break; |
145 | 175 | }
|
146 | 176 | }
|
| 177 | + if (NULL == caller->addr || 0 != caller->matches_cursor) ret = 0; // continue |
147 | 178 | }
|
148 |
| - |
149 |
| - if (NULL != xdl_linker_caller_addr[0] && NULL != xdl_linker_caller_addr[1] && 0 == *vendor_match) { |
150 |
| - return 1; // finish |
151 |
| - } else { |
152 |
| - return 0; // continue |
153 |
| - } |
| 179 | + return ret; |
154 | 180 | }
|
155 | 181 |
|
156 | 182 | static void xdl_linker_init_caller_addr_impl(void) {
|
157 |
| - size_t vendor_match = sizeof(xdl_linker_vendor_path) / sizeof(xdl_linker_vendor_path[0]); |
158 |
| - xdl_iterate_phdr_impl(xdl_linker_get_caller_addr_cb, &vendor_match, XDL_DEFAULT); |
| 183 | + xdl_iterate_phdr_impl(xdl_linker_get_caller_addr_cb, NULL, XDL_DEFAULT); |
159 | 184 | }
|
160 | 185 |
|
161 | 186 | static void xdl_linker_init_caller_addr(void) {
|
@@ -186,19 +211,20 @@ void *xdl_linker_force_dlopen(const char *filename) {
|
186 | 211 | if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) {
|
187 | 212 | // == Android 7.x
|
188 | 213 | xdl_linker_lock();
|
189 |
| - for (size_t i = 0; i < sizeof(xdl_linker_caller_addr) / sizeof(xdl_linker_caller_addr[0]); i++) { |
190 |
| - if (NULL != xdl_linker_caller_addr[i]) { |
191 |
| - handle = |
192 |
| - ((xdl_linker_dlopen_n_t)xdl_linker_dlopen)(filename, RTLD_NOW, NULL, xdl_linker_caller_addr[i]); |
| 214 | + for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { |
| 215 | + xdl_linker_caller_t *caller = &xdl_linker_callers[i]; |
| 216 | + if (NULL != caller->addr) { |
| 217 | + handle = ((xdl_linker_dlopen_n_t)xdl_linker_dlopen)(filename, RTLD_NOW, NULL, caller->addr); |
193 | 218 | if (NULL != handle) break;
|
194 | 219 | }
|
195 | 220 | }
|
196 | 221 | xdl_linker_unlock();
|
197 | 222 | } else {
|
198 | 223 | // >= Android 8.0
|
199 |
| - for (size_t i = 0; i < sizeof(xdl_linker_caller_addr) / sizeof(xdl_linker_caller_addr[0]); i++) { |
200 |
| - if (NULL != xdl_linker_caller_addr[i]) { |
201 |
| - handle = ((xdl_linker_dlopen_o_t)xdl_linker_dlopen)(filename, RTLD_NOW, xdl_linker_caller_addr[i]); |
| 224 | + for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { |
| 225 | + xdl_linker_caller_t *caller = &xdl_linker_callers[i]; |
| 226 | + if (NULL != caller->addr) { |
| 227 | + handle = ((xdl_linker_dlopen_o_t)xdl_linker_dlopen)(filename, RTLD_NOW, caller->addr); |
202 | 228 | if (NULL != handle) break;
|
203 | 229 | }
|
204 | 230 | }
|
|
0 commit comments