blob: ca8ffbcbfa3fcffa8ee2d3281f78a7ed83a36de3 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002 * Copyright (C) 2008 The Android Open Source Project
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003 * 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
Dmitriy Ivanov19133522015-06-02 17:36:54 -070029#include <android/api-level.h>
Elliott Hughes46882792012-08-03 16:49:39 -070030#include <errno.h>
31#include <fcntl.h>
Elliott Hughes0266ae52014-02-10 17:46:57 -080032#include <inttypes.h>
Elliott Hughes46882792012-08-03 16:49:39 -070033#include <pthread.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
Elliott Hughes46882792012-08-03 16:49:39 -070037#include <sys/mman.h>
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -080038#include <sys/param.h>
Elliott Hughes46882792012-08-03 16:49:39 -070039#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070041#include <new>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070042#include <string>
Dmitriy Ivanovb4827502015-09-28 16:38:31 -070043#include <unordered_map>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070044#include <vector>
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070045
Elliott Hughes46882792012-08-03 16:49:39 -070046// Private C library headers.
Mingwei Shibe910522015-11-12 07:02:14 +000047#include "private/bionic_globals.h"
Elliott Hugheseb847bc2013-10-09 15:50:50 -070048#include "private/bionic_tls.h"
49#include "private/KernelArgumentBlock.h"
50#include "private/ScopedPthreadMutexLocker.h"
Dmitriy Ivanov14669a92014-09-05 16:42:53 -070051#include "private/ScopeGuard.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080052
53#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070054#include "linker_block_allocator.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080055#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070056#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080057#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070058#include "linker_dlwarning.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070059#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070060#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020061#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080062#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080063#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070064#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080065
Elliott Hughes939a7e02015-12-04 15:27:46 -080066#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070067#include "android-base/stringprintf.h"
Josh Gao3cc387e2016-06-15 18:33:26 -070068#include "debuggerd/client.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000069#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080070
Josh Gao93c0f5e2015-10-06 11:08:13 -070071extern void __libc_init_globals(KernelArgumentBlock&);
Elliott Hughes1801db32015-06-08 18:04:00 -070072extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
73
Mingwei Shibe910522015-11-12 07:02:14 +000074extern "C" void _start();
75
Elliott Hughes1801db32015-06-08 18:04:00 -070076// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080077#undef ELF_ST_TYPE
78#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
79
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070080static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070081
Elliott Hughes0266ae52014-02-10 17:46:57 -080082static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080083
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070084static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
85static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020086
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070087static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070088static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070089
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -070090static soinfo* solist;
91static soinfo* sonext;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -070092static soinfo* somain; // main process, always the one after libdl_info
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080093
Elliott Hughes1728b232014-05-14 10:02:03 -070094static const char* const kDefaultLdPaths[] = {
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070095#if defined(__LP64__)
Elliott Hughes011bc0b2013-10-08 14:27:10 -070096 "/system/lib64",
Dimitry Ivanov88f51112016-02-01 23:00:55 -080097 "/vendor/lib64",
Elliott Hughes011bc0b2013-10-08 14:27:10 -070098#else
Elliott Hughes124fae92012-10-31 14:20:03 -070099 "/system/lib",
Dimitry Ivanov88f51112016-02-01 23:00:55 -0800100 "/vendor/lib",
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700101#endif
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700102 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -0700103};
David Bartleybc3a5c22009-06-02 18:27:28 -0700104
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700105static const char* const kAsanDefaultLdPaths[] = {
106#if defined(__LP64__)
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700107 "/data/lib64",
108 "/system/lib64",
Dimitry Ivanov88f51112016-02-01 23:00:55 -0800109 "/data/vendor/lib64",
110 "/vendor/lib64",
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700111#else
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700112 "/data/lib",
113 "/system/lib",
Dimitry Ivanov88f51112016-02-01 23:00:55 -0800114 "/data/vendor/lib",
115 "/vendor/lib",
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700116#endif
117 nullptr
118};
119
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700120static bool is_system_library(const std::string& realpath) {
121 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
122 if (file_is_in_dir(realpath, dir)) {
123 return true;
124 }
125 }
126 return false;
127}
128
129#if defined(__LP64__)
130static const char* const kSystemLibDir = "/system/lib64";
131#else
132static const char* const kSystemLibDir = "/system/lib";
133#endif
134
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700135// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
136// gradually remove libraries from this list until it is gone.
137static bool is_greylisted(const char* name, const soinfo* needed_by) {
138 static const char* const kLibraryGreyList[] = {
139 "libandroid_runtime.so",
140 "libbinder.so",
141 "libcrypto.so",
142 "libcutils.so",
143 "libexpat.so",
144 "libgui.so",
145 "libmedia.so",
146 "libnativehelper.so",
147 "libskia.so",
148 "libssl.so",
149 "libstagefright.so",
150 "libsqlite.so",
151 "libui.so",
152 "libutils.so",
153 "libvorbisidec.so",
154 nullptr
155 };
156
157 // limit greylisting to apps targeting sdk version 23 and below
158 if (get_application_target_sdk_version() > 23) {
159 return false;
160 }
161
162 // if the library needed by a system library - implicitly assume it
163 // is greylisted
164
165 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
166 return true;
167 }
168
169 // if this is an absolute path - make sure it points to /system/lib(64)
170 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
171 // and reduce the path to basename
172 name = basename(name);
173 }
174
175 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
176 if (strcmp(name, kLibraryGreyList[i]) == 0) {
177 return true;
178 }
179 }
180
181 return false;
182}
183// END OF WORKAROUND
184
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700185static const char* const* g_default_ld_paths;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700186static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800187
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700188static std::vector<soinfo*> g_ld_preloads;
Matt Fischer4fd42c12009-12-31 12:09:10 -0600189
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700190static bool g_public_namespace_initialized;
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700191static soinfo_list_t g_public_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700192
Dimitry Ivanovb996d602016-07-11 18:11:39 -0700193int g_ld_debug_verbosity;
194abort_msg_t* g_abort_message = nullptr; // For debuggerd.
Dimitry Ivanov55437462016-07-20 15:33:07 -0700195
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800196#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700197struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700198 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700199};
200
201static linker_stats_t linker_stats;
202
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800203void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700204 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700205}
206#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800207void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700208}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800209#endif
210
211#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800212uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800213#endif
214
Elliott Hughesbedfe382012-08-14 14:07:59 -0700215static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800216 if (info->is_linker() || info->is_main_executable()) {
217 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700218 return;
219 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800220
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800221 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000222
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800223 map->l_addr = info->load_bias;
224 // link_map l_name field is not const.
225 map->l_name = const_cast<char*>(info->get_realpath());
226 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000227
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800228 CHECK(map->l_name != nullptr);
229 CHECK(map->l_name[0] != '\0');
230
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800231 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700232}
233
Elliott Hughesbedfe382012-08-14 14:07:59 -0700234static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800235 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800236}
237
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700238LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
239 return g_soinfo_links_allocator.alloc();
240}
241
242void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
243 g_soinfo_links_allocator.free(entry);
244}
245
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700246LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
247 return g_namespace_list_allocator.alloc();
248}
249
250void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
251 g_namespace_list_allocator.free(entry);
252}
253
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700254static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
255 struct stat* file_stat, off64_t file_offset,
256 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700257 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200258 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700259 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200260 }
261
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700262 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
263 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700264
Magnus Malmbornba98d922012-09-12 13:00:55 +0200265 sonext->next = si;
266 sonext = si;
267
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700268 si->generate_handle();
269 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700270
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700271 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200272 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800273}
274
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800275static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700276 if (si == nullptr) {
277 return;
278 }
279
280 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800281 if (!si->is_mapped_by_caller()) {
282 munmap(reinterpret_cast<void*>(si->base), si->size);
283 } else {
284 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
285 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
286 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
287 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700288 }
289
290 soinfo *prev = nullptr, *trav;
291
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700292 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700293
294 for (trav = solist; trav != nullptr; trav = trav->next) {
295 if (trav == si) {
296 break;
Elliott Hughes46882792012-08-03 16:49:39 -0700297 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700298 prev = trav;
299 }
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800300
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700301 if (trav == nullptr) {
302 // si was not in solist
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700303 DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700304 return;
305 }
Elliott Hughes46882792012-08-03 16:49:39 -0700306
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700307 // clear links to/from si
308 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700309
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700310 // prev will never be null, because the first entry in solist is
311 // always the static libdl_info.
312 prev->next = si->next;
313 if (si == sonext) {
314 sonext = prev;
315 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800316
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700317 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700318 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800319}
320
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700321static void parse_path(const char* path, const char* delimiters,
322 std::vector<std::string>* resolved_paths) {
323 std::vector<std::string> paths;
324 split_path(path, delimiters, &paths);
325 resolve_paths(paths, resolved_paths);
326}
327
Elliott Hughescade4c32012-12-20 14:42:14 -0800328static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700329 std::vector<std::string> ld_libary_paths;
330 parse_path(path, ":", &ld_libary_paths);
331 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800332}
333
334static void parse_LD_PRELOAD(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700335 g_ld_preload_names.clear();
336 if (path != nullptr) {
337 // We have historically supported ':' as well as ' ' in LD_PRELOAD.
338 g_ld_preload_names = android::base::Split(path, " :");
Dimitry Ivanovd799b2b2016-05-24 14:29:56 -0700339 std::remove_if(g_ld_preload_names.begin(),
340 g_ld_preload_names.end(),
341 [] (const std::string& s) { return s.empty(); });
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700342 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800343}
344
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700345static bool realpath_fd(int fd, std::string* realpath) {
346 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700347 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700348 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700349 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700350 return false;
351 }
352
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700353 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700354 return true;
355}
356
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700357#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700358
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700359// For a given PC, find the .so that it belongs to.
360// Returns the base address of the .ARM.exidx section
361// for that .so, and the number of 8-byte entries
362// in that section (via *pcount).
363//
364// Intended to be called by libc's __gnu_Unwind_Find_exidx().
365//
366// This function is exposed via dlfcn.cpp and libdl.so.
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800367_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800368 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800369
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700370 for (soinfo* si = solist; si != 0; si = si->next) {
371 if ((addr >= si->base) && (addr < (si->base + si->size))) {
372 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800373 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800374 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700375 }
376 *pcount = 0;
377 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800378}
Elliott Hughes46882792012-08-03 16:49:39 -0700379
Christopher Ferris24053a42013-08-19 17:45:09 -0700380#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700381
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700382// Here, we only have to provide a callback to iterate across all the
383// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700384int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700385 int rv = 0;
386 for (soinfo* si = solist; si != nullptr; si = si->next) {
387 dl_phdr_info dl_info;
388 dl_info.dlpi_addr = si->link_map_head.l_addr;
389 dl_info.dlpi_name = si->link_map_head.l_name;
390 dl_info.dlpi_phdr = si->phdr;
391 dl_info.dlpi_phnum = si->phnum;
392 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
393 if (rv != 0) {
394 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800395 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700396 }
397 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800398}
Elliott Hughes46882792012-08-03 16:49:39 -0700399
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800400
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700401bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700402 soinfo** si_found_in, const soinfo_list_t& global_group,
403 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800404 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700405 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700406
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700407 /* "This element's presence in a shared object library alters the dynamic linker's
408 * symbol resolution algorithm for references within the library. Instead of starting
409 * a symbol search with the executable file, the dynamic linker starts from the shared
410 * object itself. If the shared object fails to supply the referenced symbol, the
411 * dynamic linker then searches the executable file and other shared objects as usual."
412 *
413 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
414 *
415 * Note that this is unlikely since static linker avoids generating
416 * relocations for -Bsymbolic linked dynamic executables.
417 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700418 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700419 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700420 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
421 return false;
422 }
423
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700424 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700425 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700426 }
427 }
428
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700429 // 1. Look for it in global_group
430 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700431 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700432 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700433 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700434 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700435 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
436 error = true;
437 return false;
438 }
439
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700440 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700441 *si_found_in = global_si;
442 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700443 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700444
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700445 return true;
446 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700447
448 if (error) {
449 return false;
450 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700451 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700452
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700453 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700454 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700455 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700456 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700457 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700458 // we already did this - skip
459 return true;
460 }
461
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700462 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700463 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700464 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
465 error = true;
466 return false;
467 }
468
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700469 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700470 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700471 return false;
472 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700473
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700474 return true;
475 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700476
477 if (error) {
478 return false;
479 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700480 }
481
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700482 if (s != nullptr) {
483 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
484 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700485 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
486 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700487 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700488 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700489
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700490 *symbol = s;
491 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700492}
493
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800494class ProtectedDataGuard {
495 public:
496 ProtectedDataGuard() {
497 if (ref_count_++ == 0) {
498 protect_data(PROT_READ | PROT_WRITE);
499 }
500 }
501
502 ~ProtectedDataGuard() {
503 if (ref_count_ == 0) { // overflow
504 __libc_fatal("Too many nested calls to dlopen()");
505 }
506
507 if (--ref_count_ == 0) {
508 protect_data(PROT_READ);
509 }
510 }
511 private:
512 void protect_data(int protection) {
513 g_soinfo_allocator.protect_all(protection);
514 g_soinfo_links_allocator.protect_all(protection);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700515 g_namespace_allocator.protect_all(protection);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700516 g_namespace_list_allocator.protect_all(protection);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800517 }
518
519 static size_t ref_count_;
520};
521
522size_t ProtectedDataGuard::ref_count_ = 0;
523
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700524// Each size has it's own allocator.
525template<size_t size>
526class SizeBasedAllocator {
527 public:
528 static void* alloc() {
529 return allocator_.alloc();
530 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700531
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700532 static void free(void* ptr) {
533 allocator_.free(ptr);
534 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700535
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700536 private:
537 static LinkerBlockAllocator allocator_;
538};
539
540template<size_t size>
541LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
542
543template<typename T>
544class TypeBasedAllocator {
545 public:
546 static T* alloc() {
547 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
548 }
549
550 static void free(T* ptr) {
551 SizeBasedAllocator<sizeof(T)>::free(ptr);
552 }
553};
554
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700555class LoadTask {
556 public:
557 struct deleter_t {
558 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700559 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700560 TypeBasedAllocator<LoadTask>::free(t);
561 }
562 };
563
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700564 static deleter_t deleter;
565
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700566 static LoadTask* create(const char* name, soinfo* needed_by,
567 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700568 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700569 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700570 }
571
572 const char* get_name() const {
573 return name_;
574 }
575
576 soinfo* get_needed_by() const {
577 return needed_by_;
578 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700579
580 soinfo* get_soinfo() const {
581 return si_;
582 }
583
584 void set_soinfo(soinfo* si) {
585 si_ = si;
586 }
587
588 off64_t get_file_offset() const {
589 return file_offset_;
590 }
591
592 void set_file_offset(off64_t offset) {
593 file_offset_ = offset;
594 }
595
596 int get_fd() const {
597 return fd_;
598 }
599
600 void set_fd(int fd, bool assume_ownership) {
601 fd_ = fd;
602 close_fd_ = assume_ownership;
603 }
604
605 const android_dlextinfo* get_extinfo() const {
606 return extinfo_;
607 }
608
609 void set_extinfo(const android_dlextinfo* extinfo) {
610 extinfo_ = extinfo;
611 }
612
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700613 bool is_dt_needed() const {
614 return is_dt_needed_;
615 }
616
617 void set_dt_needed(bool is_dt_needed) {
618 is_dt_needed_ = is_dt_needed;
619 }
620
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700621 const ElfReader& get_elf_reader() const {
622 CHECK(si_ != nullptr);
623 return (*elf_readers_map_)[si_];
624 }
625
626 ElfReader& get_elf_reader() {
627 CHECK(si_ != nullptr);
628 return (*elf_readers_map_)[si_];
629 }
630
631 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
632 return elf_readers_map_;
633 }
634
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 }
639
640 bool load() {
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();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800648 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700649 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 }
655
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700656 private:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700657 LoadTask(const char* name, soinfo* needed_by,
658 std::unordered_map<const soinfo*, ElfReader>* readers_map)
659 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700660 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
661 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700662
663 ~LoadTask() {
664 if (fd_ != -1 && close_fd_) {
665 close(fd_);
666 }
667 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700668
669 const char* name_;
670 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700671 soinfo* si_;
672 const android_dlextinfo* extinfo_;
673 int fd_;
674 bool close_fd_;
675 off64_t file_offset_;
676 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700677 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
678 bool is_dt_needed_;
679 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700680
681 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
682};
683
Ningsheng Jiane93be992014-09-16 15:22:10 +0800684LoadTask::deleter_t LoadTask::deleter;
685
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700686template <typename T>
687using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
688
689typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700690typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700691typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700692
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700693
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700694// This function walks down the tree of soinfo dependencies
695// in breadth-first order and
696// * calls action(soinfo* si) for each node, and
697// * terminates walk if action returns false.
698//
699// walk_dependencies_tree returns false if walk was terminated
700// by the action and true otherwise.
701template<typename F>
702static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700703 SoinfoLinkedList visit_list;
704 SoinfoLinkedList visited;
705
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700706 for (size_t i = 0; i < root_soinfos_size; ++i) {
707 visit_list.push_back(root_soinfos[i]);
708 }
709
710 soinfo* si;
711 while ((si = visit_list.pop_front()) != nullptr) {
712 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700713 continue;
714 }
715
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700716 if (!action(si)) {
717 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700718 }
719
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700720 visited.push_back(si);
721
722 si->get_children().for_each([&](soinfo* child) {
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700723 visit_list.push_back(child);
724 });
725 }
726
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700727 return true;
728}
729
730
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700731static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800732 soinfo** found, SymbolName& symbol_name,
733 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700734 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700735 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700736
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700737 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
738 if (skip_lookup) {
739 skip_lookup = current_soinfo != skip_until;
740 return true;
741 }
742
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800743 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700744 result = nullptr;
745 return false;
746 }
747
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700748 if (result != nullptr) {
749 *found = current_soinfo;
750 return false;
751 }
752
753 return true;
754 });
755
756 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800757}
758
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800759static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
760 const char* name,
761 const version_info* vi,
762 soinfo** found,
763 soinfo* caller,
764 void* handle);
765
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700766// This is used by dlsym(3). It performs symbol lookup only within the
767// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800768static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
769 const char* name, const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700770 // According to man dlopen(3) and posix docs in the case when si is handle
771 // of the main executable we need to search not only in the executable and its
772 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
773 //
774 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
775 // libraries and they are loaded in breath-first (correct) order we can just execute
776 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
777 if (si == somain) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800778 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700779 }
780
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700781 SymbolName symbol_name(name);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800782 return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700783}
784
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800785/* This is used by dlsym(3) to performs a global symbol lookup. If the
786 start value is null (for RTLD_DEFAULT), the search starts at the
787 beginning of the global solist. Otherwise the search starts at the
788 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700789 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800790static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
791 const char* name,
792 const version_info* vi,
793 soinfo** found,
794 soinfo* caller,
795 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800796 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800797
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700798 auto& soinfo_list = ns->soinfo_list();
799 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700800
801 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700802 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700803 return nullptr;
804 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700805 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700806 CHECK (it != soinfo_list.end());
807 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700808 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800809 }
810
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700811 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700812 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700813 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700814 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
815 // if the library is opened by application with target api level <= 22
816 // See http://b/21565766
817 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700818 continue;
819 }
820
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800821 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700822 return nullptr;
823 }
824
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700825 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800826 *found = si;
827 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600828 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800829 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600830
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700831 // If not found - use dlsym_handle_lookup for caller's
832 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700833 // case we already did it.
834 if (s == nullptr && caller != nullptr &&
835 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700836 return dlsym_handle_lookup(caller->get_local_group_root(),
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800837 (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700838 }
839
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700840 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700841 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
842 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800843 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800844
Elliott Hughescade4c32012-12-20 14:42:14 -0800845 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800846}
847
Kito Chengfa8c05d2013-03-12 14:58:06 +0800848soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800849 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700850 for (soinfo* si = solist; si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800851 if (address >= si->base && address - si->base < si->size) {
852 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600853 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800854 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700855 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600856}
857
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700858class ZipArchiveCache {
859 public:
860 ZipArchiveCache() {}
861 ~ZipArchiveCache();
862
863 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
864 private:
865 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
866
867 std::unordered_map<std::string, ZipArchiveHandle> cache_;
868};
869
870bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
871 std::string key(zip_path);
872
873 auto it = cache_.find(key);
874 if (it != cache_.end()) {
875 *handle = it->second;
876 return true;
877 }
878
879 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
880 if (fd == -1) {
881 return false;
882 }
883
884 if (OpenArchiveFd(fd, "", handle) != 0) {
885 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700886 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700887 close(fd);
888 return false;
889 }
890
891 cache_[key] = *handle;
892 return true;
893}
894
895ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700896 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700897 CloseArchive(it.second);
898 }
899}
900
901static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700902 const char* const input_path,
903 off64_t* file_offset, std::string* realpath) {
904 std::string normalized_path;
905 if (!normalize_path(input_path, &normalized_path)) {
906 return -1;
907 }
908
909 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700910 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000911
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700912 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000913 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700914 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000915 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700916 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000917 if (separator == nullptr) {
918 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700919 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000920
921 char buf[512];
922 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
923 PRINT("Warning: ignoring very long library path: %s", path);
924 return -1;
925 }
926
927 buf[separator - path] = '\0';
928
929 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700930 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000931 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
932 if (fd == -1) {
933 return -1;
934 }
935
936 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700937 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000938 // invalid zip-file (?)
939 close(fd);
940 return -1;
941 }
942
Simon Baldwinaef71952015-01-16 13:22:54 +0000943 ZipEntry entry;
944
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700945 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000946 // Entry was not found.
947 close(fd);
948 return -1;
949 }
950
951 // Check if it is properly stored
952 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
953 close(fd);
954 return -1;
955 }
956
957 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700958
959 if (realpath_fd(fd, realpath)) {
960 *realpath += separator;
961 } else {
962 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
963 normalized_path.c_str());
964 *realpath = normalized_path;
965 }
966
Simon Baldwinaef71952015-01-16 13:22:54 +0000967 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800968}
969
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700970static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
971 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
972 if (n < 0 || n >= static_cast<int>(buf_size)) {
973 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
974 return false;
975 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000976
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700977 return true;
978}
979
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700980static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
981 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700982 const std::vector<std::string>& paths,
983 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700984 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700985 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700986 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700987 continue;
988 }
989
990 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700991 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700992 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +0000993 }
994
995 if (fd == -1) {
996 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
997 if (fd != -1) {
998 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700999 if (!realpath_fd(fd, realpath)) {
1000 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
1001 *realpath = buf;
1002 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001003 }
1004 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001005
1006 if (fd != -1) {
1007 return fd;
1008 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001009 }
1010
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001011 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001012}
1013
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001014static int open_library(android_namespace_t* ns,
1015 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001016 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001017 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -07001018 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001019
Elliott Hughes124fae92012-10-31 14:20:03 -07001020 // If the name contains a slash, we should attempt to open it directly and not search the paths.
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001021 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001022 int fd = -1;
1023
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001024 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001025 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1026 }
1027
1028 if (fd == -1) {
1029 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001030 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001031 *file_offset = 0;
1032 if (!realpath_fd(fd, realpath)) {
1033 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1034 *realpath = name;
1035 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001036 }
1037 }
1038
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001039 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001040 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001041
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001042 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1043 int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001044 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001045 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001046 // Check if the library is accessible
1047 if (fd != -1 && !ns->is_accessible(*realpath)) {
1048 fd = -1;
1049 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001050 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001051
Elliott Hughes124fae92012-10-31 14:20:03 -07001052 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001053 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001054 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001055
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001056 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
1057 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
1058 // try searching for it on default_namespace default_library_path
1059 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1060 g_default_namespace.get_default_library_paths(), realpath);
1061 }
1062 // END OF WORKAROUND
1063
Elliott Hughes124fae92012-10-31 14:20:03 -07001064 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001065}
1066
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001067static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
1068#if !defined(__LP64__)
1069 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Dmitriy Ivanov19133522015-06-02 17:36:54 -07001070 if (get_application_target_sdk_version() <= 22) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001071 const char* bname = basename(dt_needed);
1072 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001073 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1074 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001075 }
1076
1077 return bname;
1078 }
1079#endif
1080 return dt_needed;
1081}
1082
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001083template<typename F>
1084static void for_each_dt_needed(const soinfo* si, F action) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001085 for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001086 if (d->d_tag == DT_NEEDED) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001087 action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
Dima Zavin2e855792009-05-20 18:28:09 -07001088 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001089 }
1090}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001091
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001092template<typename F>
1093static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1094 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1095 if (d->d_tag == DT_NEEDED) {
1096 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1097 }
1098 }
1099}
1100
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001101static bool load_library(android_namespace_t* ns,
1102 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001103 LoadTaskList* load_tasks,
1104 int rtld_flags,
1105 const std::string& realpath) {
1106 off64_t file_offset = task->get_file_offset();
1107 const char* name = task->get_name();
1108 const android_dlextinfo* extinfo = task->get_extinfo();
1109
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001110 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001111 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001112 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001113 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001114 if (file_offset < 0) {
1115 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001116 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001117 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001118
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001119 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001120 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001121 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001122 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001123 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001124 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001125 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1126 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001127 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001128 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001129
1130 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001131 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1132 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001133 auto predicate = [&](soinfo* si) {
1134 return si->get_st_dev() != 0 &&
1135 si->get_st_ino() != 0 &&
1136 si->get_st_dev() == file_stat.st_dev &&
1137 si->get_st_ino() == file_stat.st_ino &&
1138 si->get_file_offset() == file_offset;
1139 };
1140
1141 soinfo* si = ns->soinfo_list().find_if(predicate);
1142
1143 // check public namespace
1144 if (si == nullptr) {
1145 si = g_public_namespace.find_if(predicate);
1146 if (si != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001147 ns->add_soinfo(si);
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001148 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001149 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001150
1151 if (si != nullptr) {
1152 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1153 "will return existing soinfo", name, si->get_realpath());
1154 task->set_soinfo(si);
1155 return true;
1156 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001157 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001158
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001159 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001160 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001161 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001162 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001163
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001164 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001165 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
1166 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1167 if (is_greylisted(name, needed_by)) {
1168 // print warning only if needed by non-system library
1169 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1170 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1171 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1172 needed_or_dlopened_by->get_realpath();
1173 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1174 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1175 " will be removed in future releases of Android.",
1176 name, realpath.c_str(), sopath, ns->get_name());
1177 add_dlwarning(sopath, "unauthorized access to", name);
1178 }
1179 } else {
1180 // do not load libraries if they are not accessible for the specified namespace.
1181 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1182 "(unknown)" :
1183 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001184
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001185 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1186 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001187
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001188 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1189 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1190 " permitted_paths=\"%s\"]",
1191 name, realpath.c_str(),
1192 needed_or_dlopened_by,
1193 ns->get_name(),
1194 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1195 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1196 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1197 return false;
1198 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001199 }
1200
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001201 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001202 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001203 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001204 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001205
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001206 task->set_soinfo(si);
1207
1208 // Read the ELF header and some of the segments.
1209 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001210 soinfo_free(si);
1211 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001212 return false;
1213 }
1214
1215 // find and set DT_RUNPATH and dt_soname
1216 // Note that these field values are temporary and are
1217 // going to be overwritten on soinfo::prelink_image
1218 // with values from PT_LOAD segments.
1219 const ElfReader& elf_reader = task->get_elf_reader();
1220 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1221 if (d->d_tag == DT_RUNPATH) {
1222 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1223 }
1224 if (d->d_tag == DT_SONAME) {
1225 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1226 }
1227 }
1228
1229 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1230 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001231 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001232
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001233 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001234}
1235
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001236static bool load_library(android_namespace_t* ns,
1237 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001238 ZipArchiveCache* zip_archive_cache,
1239 LoadTaskList* load_tasks,
1240 int rtld_flags) {
1241 const char* name = task->get_name();
1242 soinfo* needed_by = task->get_needed_by();
1243 const android_dlextinfo* extinfo = task->get_extinfo();
1244
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001245 off64_t file_offset;
1246 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001247 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001248 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001249 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1250 file_offset = extinfo->library_fd_offset;
1251 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001252
1253 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1254 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1255 "Will use given name.", name);
1256 realpath = name;
1257 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001258
1259 task->set_fd(extinfo->library_fd, false);
1260 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001261 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001262 }
1263
1264 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001265 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001266 if (fd == -1) {
1267 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001268 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001269 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001270
1271 task->set_fd(fd, true);
1272 task->set_file_offset(file_offset);
1273
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001274 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001275}
1276
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001277// Returns true if library was found and false in 2 cases
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001278// 1. (for default namespace only) The library was found but loaded under different
1279// target_sdk_version (*candidate != nullptr)
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001280// 2. The library was not found by soname (*candidate is nullptr)
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001281static bool find_loaded_library_by_soname(android_namespace_t* ns,
1282 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001283 *candidate = nullptr;
1284
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001285 // Ignore filename with path.
1286 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001287 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001288 }
1289
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001290 uint32_t target_sdk_version = get_application_target_sdk_version();
1291
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001292 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001293 const char* soname = si->get_soname();
1294 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001295 // If the library was opened under different target sdk version
1296 // skip this step and try to reopen it. The exceptions are
1297 // "libdl.so" and global group. There is no point in skipping
1298 // them because relocation process is going to use them
1299 // in any case.
1300 bool is_libdl = si == solist;
1301 if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001302 !si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
1303 ns != &g_default_namespace) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001304 *candidate = si;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001305 return false;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001306 } else if (*candidate == nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001307 // for the different sdk version in the default namespace
1308 // remember the first library.
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001309 *candidate = si;
1310 }
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001311 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001312
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001313 return true;
1314 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001315}
1316
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001317static bool find_library_internal(android_namespace_t* ns,
1318 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001319 ZipArchiveCache* zip_archive_cache,
1320 LoadTaskList* load_tasks,
1321 int rtld_flags) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001322 soinfo* candidate;
1323
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001324 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001325 task->set_soinfo(candidate);
1326 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001327 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001328
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001329 if (ns != &g_default_namespace) {
1330 // check public namespace
1331 candidate = g_public_namespace.find_if([&](soinfo* si) {
1332 return strcmp(task->get_name(), si->get_soname()) == 0;
1333 });
1334
1335 if (candidate != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001336 ns->add_soinfo(candidate);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001337 task->set_soinfo(candidate);
1338 return true;
1339 }
1340 }
1341
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001342 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001343 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001344 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001345 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001346
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001347 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001348 return true;
1349 } else {
1350 // In case we were unable to load the library but there
1351 // is a candidate loaded under the same soname but different
1352 // sdk level - return it anyways.
1353 if (candidate != nullptr) {
1354 task->set_soinfo(candidate);
1355 return true;
1356 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001357 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001358
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001359 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001360}
1361
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001362static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001363static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001364
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001365// TODO: this is slightly unusual way to construct
1366// the global group for relocation. Not every RTLD_GLOBAL
1367// library is included in this group for backwards-compatibility
1368// reasons.
1369//
1370// This group consists of the main executable, LD_PRELOADs
1371// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001372static soinfo_list_t make_global_group(android_namespace_t* ns) {
1373 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001374 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001375 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1376 global_group.push_back(si);
1377 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001378 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001379
1380 return global_group;
1381}
1382
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001383// This function provides a list of libraries to be shared
1384// by the namespace. For the default namespace this is the global
1385// group (see make_global_group). For all others this is a group
1386// of RTLD_GLOBAL libraries (which includes the global group from
1387// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001388static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001389 if (ns == &g_default_namespace) {
1390 return make_global_group(ns);
1391 }
1392
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001393 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001394 ns->soinfo_list().for_each([&](soinfo* si) {
1395 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1396 shared_group.push_back(si);
1397 }
1398 });
1399
1400 return shared_group;
1401}
1402
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001403static void shuffle(std::vector<LoadTask*>* v) {
1404 for (size_t i = 0, size = v->size(); i < size; ++i) {
1405 size_t n = size - i;
1406 size_t r = arc4random_uniform(n);
1407 std::swap((*v)[n-1], (*v)[r]);
1408 }
1409}
1410
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001411// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1412// not their transitive dependencies) as children of the start_with library.
1413// This is false when find_libraries is called for dlopen(), when newly loaded
1414// libraries must form a disjoint tree.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001415static bool find_libraries(android_namespace_t* ns,
1416 soinfo* start_with,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001417 const char* const library_names[],
1418 size_t library_names_count, soinfo* soinfos[],
1419 std::vector<soinfo*>* ld_preloads,
1420 size_t ld_preloads_count, int rtld_flags,
1421 const android_dlextinfo* extinfo,
1422 bool add_as_children) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001423 // Step 0: prepare.
1424 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001425 std::unordered_map<const soinfo*, ElfReader> readers_map;
1426
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001427 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001428 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001429 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001430 }
1431
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001432 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001433 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001434
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001435 // If soinfos array is null allocate one on stack.
1436 // The array is needed in case of failure; for example
1437 // when library_names[] = {libone.so, libtwo.so} and libone.so
1438 // is loaded correctly but libtwo.so failed for some reason.
1439 // In this case libone.so should be unloaded on return.
1440 // See also implementation of failure_guard below.
1441
1442 if (soinfos == nullptr) {
1443 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1444 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1445 memset(soinfos, 0, soinfos_size);
1446 }
1447
1448 // list of libraries to link - see step 2.
1449 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001450
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001451 auto scope_guard = make_scope_guard([&]() {
1452 for (LoadTask* t : load_tasks) {
1453 LoadTask::deleter(t);
1454 }
1455 });
1456
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001457 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001458 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001459 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001460 });
1461
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001462 ZipArchiveCache zip_archive_cache;
1463
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001464 // Step 1: expand the list of load_tasks to include
1465 // all DT_NEEDED libraries (do not load them just yet)
1466 for (size_t i = 0; i<load_tasks.size(); ++i) {
1467 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001468 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001469
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001470 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001471 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001472 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001473
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001474 if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001475 return false;
1476 }
1477
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001478 soinfo* si = task->get_soinfo();
1479
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001480 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001481 needed_by->add_child(si);
1482 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001483
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001484 if (si->is_linked()) {
1485 si->increment_ref_count();
1486 }
1487
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001488 // When ld_preloads is not null, the first
1489 // ld_preloads_count libs are in fact ld_preloads.
1490 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001491 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001492 }
1493
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001494 if (soinfos_count < library_names_count) {
1495 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001496 }
1497 }
1498
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001499 // Step 2: Load libraries in random order (see b/24047022)
1500 LoadTaskList load_list;
1501 for (auto&& task : load_tasks) {
1502 soinfo* si = task->get_soinfo();
1503 auto pred = [&](const LoadTask* t) {
1504 return t->get_soinfo() == si;
1505 };
1506
1507 if (!si->is_linked() &&
1508 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1509 load_list.push_back(task);
1510 }
1511 }
1512 shuffle(&load_list);
1513
1514 for (auto&& task : load_list) {
1515 if (!task->load()) {
1516 return false;
1517 }
1518 }
1519
1520 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1521 for (auto&& task : load_tasks) {
1522 soinfo* si = task->get_soinfo();
1523 if (!si->is_linked() && !si->prelink_image()) {
1524 return false;
1525 }
1526 }
1527
1528 // Step 4: Add LD_PRELOADed libraries to the global group for
1529 // future runs. There is no need to explicitly add them to
1530 // the global group for this run because they are going to
1531 // appear in the local group in the correct order.
1532 if (ld_preloads != nullptr) {
1533 for (auto&& si : *ld_preloads) {
1534 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1535 }
1536 }
1537
1538
1539 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001540 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001541 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001542 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1543 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001544 [&] (soinfo* si) {
1545 local_group.push_back(si);
1546 return true;
1547 });
1548
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001549 // We need to increment ref_count in case
1550 // the root of the local group was not linked.
1551 bool was_local_group_root_linked = local_group.front()->is_linked();
1552
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001553 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001554 if (!si->is_linked()) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001555 if (!si->link_image(global_group, local_group, extinfo)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001556 return false;
1557 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001558 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001559
1560 return true;
1561 });
1562
1563 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001564 local_group.for_each([](soinfo* si) {
1565 if (!si->is_linked()) {
1566 si->set_linked();
1567 }
1568 });
1569
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001570 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001571 }
1572
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001573 if (!was_local_group_root_linked) {
1574 local_group.front()->increment_ref_count();
1575 }
1576
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001577 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001578}
1579
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001580static soinfo* find_library(android_namespace_t* ns,
1581 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001582 const android_dlextinfo* extinfo,
1583 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001584 soinfo* si;
1585
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001586 if (name == nullptr) {
1587 si = somain;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001588 } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001589 extinfo, /* add_as_children */ false)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001590 return nullptr;
1591 }
1592
Elliott Hughesd23736e2012-11-01 15:16:56 -07001593 return si;
1594}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001595
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001596static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001597 if (root->is_linked()) {
1598 root = root->get_local_group_root();
1599 }
1600
1601 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001602 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001603 return;
1604 }
1605
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001606 soinfo_unload(&root, 1);
1607}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001608
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001609static void soinfo_unload(soinfo* soinfos[], size_t count) {
1610 // Note that the library can be loaded but not linked;
1611 // in which case there is no root but we still need
1612 // to walk the tree and unload soinfos involved.
1613 //
1614 // This happens on unsuccessful dlopen, when one of
1615 // the DT_NEEDED libraries could not be linked/found.
1616 if (count == 0) {
1617 return;
1618 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001619
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001620 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001621 for (size_t i = 0; i < count; ++i) {
1622 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001623
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001624 if (si->can_unload()) {
1625 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1626 if (ref_count == 0) {
1627 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001628 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001629 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1630 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001631 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001632 } else {
1633 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1634 return;
1635 }
1636 }
1637
1638 // This is used to identify soinfos outside of the load-group
1639 // note that we cannot have > 1 in the array and have any of them
1640 // linked. This is why we can safely use the first one.
1641 soinfo* root = soinfos[0];
1642
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001643 soinfo_list_t local_unload_list;
1644 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001645 soinfo* si = nullptr;
1646
1647 while ((si = unload_list.pop_front()) != nullptr) {
1648 if (local_unload_list.contains(si)) {
1649 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001650 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001651
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001652 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001653
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001654 if (si->has_min_version(0)) {
1655 soinfo* child = nullptr;
1656 while ((child = si->get_children().pop_front()) != nullptr) {
1657 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1658 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001659
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001660 if (local_unload_list.contains(child)) {
1661 continue;
1662 } else if (child->is_linked() && child->get_local_group_root() != root) {
1663 external_unload_list.push_back(child);
1664 } else {
1665 unload_list.push_front(child);
1666 }
1667 }
1668 } else {
1669#if !defined(__work_around_b_24465209__)
1670 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1671#else
1672 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1673 for_each_dt_needed(si, [&] (const char* library_name) {
1674 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1675 si->get_realpath(), library_name);
1676
1677 soinfo* needed = find_library(si->get_primary_namespace(),
1678 library_name, RTLD_NOLOAD, nullptr, nullptr);
1679
1680 if (needed != nullptr) {
1681 // Not found: for example if symlink was deleted between dlopen and dlclose
1682 // Since we cannot really handle errors at this point - print and continue.
1683 PRINT("warning: couldn't find %s needed by %s on unload.",
1684 library_name, si->get_realpath());
1685 return;
1686 } else if (local_unload_list.contains(needed)) {
1687 // already visited
1688 return;
1689 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1690 // external group
1691 external_unload_list.push_back(needed);
1692 } else {
1693 // local group
1694 unload_list.push_front(needed);
1695 }
1696 });
1697#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001698 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001699 }
1700
1701 local_unload_list.for_each([](soinfo* si) {
1702 si->call_destructors();
1703 });
1704
1705 while ((si = local_unload_list.pop_front()) != nullptr) {
1706 notify_gdb_of_unload(si);
1707 soinfo_free(si);
1708 }
1709
1710 while ((si = external_unload_list.pop_front()) != nullptr) {
1711 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001712 }
1713}
1714
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001715static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1716 if (sym_ver == nullptr) {
1717 return sym_name;
1718 }
1719
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001720 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001721}
1722
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001723static android_namespace_t* get_caller_namespace(soinfo* caller) {
1724 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1725}
1726
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001727void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001728 // Use basic string manipulation calls to avoid snprintf.
1729 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1730 // When debug malloc is enabled, this call returns 0. This in turn causes
1731 // snprintf to do nothing, which causes libraries to fail to load.
1732 // See b/17302493 for further details.
1733 // Once the above bug is fixed, this code can be modified to use
1734 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001735 size_t required_len = 0;
1736 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1737 required_len += strlen(g_default_ld_paths[i]) + 1;
1738 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001739 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001740 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1741 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001742 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001743 char* end = buffer;
1744 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1745 if (i > 0) *end++ = ':';
1746 end = stpcpy(end, g_default_ld_paths[i]);
1747 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001748}
1749
Elliott Hughescade4c32012-12-20 14:42:14 -08001750void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001751 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001752}
1753
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001754static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1755 if (info == nullptr) {
1756 return "(null)";
1757 }
1758
1759 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1760 " reserved_addr=%p,"
1761 " reserved_size=0x%zx,"
1762 " relro_fd=%d,"
1763 " library_fd=%d,"
1764 " library_fd_offset=0x%" PRIx64 ","
1765 " library_namespace=%s@%p]",
1766 info->flags,
1767 info->reserved_addr,
1768 info->reserved_size,
1769 info->relro_fd,
1770 info->library_fd,
1771 info->library_fd_offset,
1772 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1773 (info->library_namespace != nullptr ?
1774 info->library_namespace->get_name() : "(null)") : "(n/a)",
1775 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1776 info->library_namespace : nullptr);
1777}
1778
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001779void* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001780 void* caller_addr) {
1781 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001782 android_namespace_t* ns = get_caller_namespace(caller);
1783
1784 LD_LOG(kLogDlopen,
1785 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1786 name,
1787 flags,
1788 android_dlextinfo_to_string(extinfo).c_str(),
1789 caller == nullptr ? "(null)" : caller->get_realpath(),
1790 ns == nullptr ? "(null)" : ns->get_name(),
1791 ns);
1792
1793 auto failure_guard = make_scope_guard([&]() {
1794 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1795 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001796
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001797 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001798 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001799 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001800 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001801
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001802 if (extinfo != nullptr) {
1803 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1804 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1805 return nullptr;
1806 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001807
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001808 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001809 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001810 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1811 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001812 return nullptr;
1813 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001814
1815 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1816 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1817 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1818 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1819 return nullptr;
1820 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001821
1822 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1823 if (extinfo->library_namespace == nullptr) {
1824 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1825 return nullptr;
1826 }
1827 ns = extinfo->library_namespace;
1828 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001829 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001830
1831 ProtectedDataGuard guard;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001832 soinfo* si = find_library(ns, name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001833 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001834 failure_guard.disable();
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001835 si->call_constructors();
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001836 void* handle = si->to_handle();
1837 LD_LOG(kLogDlopen,
1838 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1839 si->get_realpath(), si->get_soname(), handle);
1840 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001841 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001842
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001843 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001844}
1845
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001846int do_dladdr(const void* addr, Dl_info* info) {
1847 // Determine if this address can be found in any library currently mapped.
1848 soinfo* si = find_containing_library(addr);
1849 if (si == nullptr) {
1850 return 0;
1851 }
1852
1853 memset(info, 0, sizeof(Dl_info));
1854
1855 info->dli_fname = si->get_realpath();
1856 // Address at which the shared object is loaded.
1857 info->dli_fbase = reinterpret_cast<void*>(si->base);
1858
1859 // Determine if any symbol in the library contains the specified address.
1860 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1861 if (sym != nullptr) {
1862 info->dli_sname = si->get_string(sym->st_name);
1863 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1864 }
1865
1866 return 1;
1867}
1868
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001869static soinfo* soinfo_from_handle(void* handle) {
1870 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1871 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1872 if (it == g_soinfo_handles_map.end()) {
1873 return nullptr;
1874 } else {
1875 return it->second;
1876 }
1877 }
1878
1879 return static_cast<soinfo*>(handle);
1880}
1881
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001882bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
1883 void* caller_addr, void** symbol) {
1884#if !defined(__LP64__)
1885 if (handle == nullptr) {
1886 DL_ERR("dlsym failed: library handle is null");
1887 return false;
1888 }
1889#endif
1890
1891 if (sym_name == nullptr) {
1892 DL_ERR("dlsym failed: symbol name is null");
1893 return false;
1894 }
1895
1896 soinfo* found = nullptr;
1897 const ElfW(Sym)* sym = nullptr;
1898 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001899 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001900
1901 version_info vi_instance;
1902 version_info* vi = nullptr;
1903
1904 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001905 vi_instance.name = sym_ver;
1906 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001907 vi = &vi_instance;
1908 }
1909
1910 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1911 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1912 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001913 soinfo* si = soinfo_from_handle(handle);
1914 if (si == nullptr) {
1915 DL_ERR("dlsym failed: invalid handle: %p", handle);
1916 return false;
1917 }
1918 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001919 }
1920
1921 if (sym != nullptr) {
1922 uint32_t bind = ELF_ST_BIND(sym->st_info);
1923
1924 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1925 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
1926 return true;
1927 }
1928
1929 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
1930 return false;
1931 }
1932
1933 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
1934 return false;
1935}
1936
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001937int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001938 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001939 soinfo* si = soinfo_from_handle(handle);
1940 if (si == nullptr) {
1941 DL_ERR("invalid handle: %p", handle);
1942 return -1;
1943 }
1944
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001945 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001946 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001947}
1948
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001949bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001950 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001951 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001952 return false;
1953 }
1954
Dimitry Ivanov54807612016-04-21 14:57:38 -07001955 if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
1956 DL_ERR("error initializing public namespace: the list of public libraries is empty.");
1957 return false;
1958 }
1959
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001960 std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001961
1962 ProtectedDataGuard guard;
1963
1964 auto failure_guard = make_scope_guard([&]() {
1965 g_public_namespace.clear();
1966 });
1967
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001968 for (const auto& soname : sonames) {
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -08001969 soinfo* candidate = nullptr;
1970
1971 find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
1972
1973 if (candidate == nullptr) {
Christopher Ferris523e2a92016-06-17 13:46:36 -07001974 DL_ERR("error initializing public namespace: a library with soname \"%s\""
1975 " was not found in the default namespace", soname.c_str());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001976 return false;
1977 }
1978
1979 candidate->set_nodelete();
1980 g_public_namespace.push_back(candidate);
1981 }
1982
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001983 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001984
1985 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001986 // When the caller is nullptr - create_namespace will take global group
1987 // from the anonymous namespace, which is fine because anonymous namespace
1988 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001989 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001990 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
Dimitry Ivanov52408632016-05-23 10:31:11 -07001991 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001992
1993 if (anon_ns == nullptr) {
1994 g_public_namespace_initialized = false;
1995 return false;
1996 }
1997 g_anonymous_namespace = anon_ns;
1998 failure_guard.disable();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001999 return true;
2000}
2001
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002002static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2003 ns->add_soinfos(soinfos);
2004 for (auto si : soinfos) {
2005 si->add_secondary_namespace(ns);
2006 }
2007}
2008
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002009android_namespace_t* create_namespace(const void* caller_addr,
2010 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002011 const char* ld_library_path,
2012 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002013 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002014 const char* permitted_when_isolated_path,
2015 android_namespace_t* parent_namespace) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002016 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002017 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002018 return nullptr;
2019 }
2020
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002021 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002022 // if parent_namespace is nullptr -> set it to the caller namespace
2023 soinfo* caller_soinfo = find_containing_library(caller_addr);
2024
2025 parent_namespace = caller_soinfo != nullptr ?
2026 caller_soinfo->get_primary_namespace() :
2027 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002028 }
2029
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002030 ProtectedDataGuard guard;
2031 std::vector<std::string> ld_library_paths;
2032 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002033 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002034
2035 parse_path(ld_library_path, ":", &ld_library_paths);
2036 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002037 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002038
2039 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2040 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002041 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002042 ns->set_ld_library_paths(std::move(ld_library_paths));
2043 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002044 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002045
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002046 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002047 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002048 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002049 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002050 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002051 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002052 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002053
2054 return ns;
2055}
2056
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002057ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002058 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2059 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2060 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002061 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2062 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002063
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002064 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002065}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002066
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002067const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2068 if (source_symver < 2 ||
2069 source_symver >= version_infos.size() ||
2070 version_infos[source_symver].name == nullptr) {
2071 return nullptr;
2072 }
2073
2074 return &version_infos[source_symver];
2075}
2076
2077void VersionTracker::add_version_info(size_t source_index,
2078 ElfW(Word) elf_hash,
2079 const char* ver_name,
2080 const soinfo* target_si) {
2081 if (source_index >= version_infos.size()) {
2082 version_infos.resize(source_index+1);
2083 }
2084
2085 version_infos[source_index].elf_hash = elf_hash;
2086 version_infos[source_index].name = ver_name;
2087 version_infos[source_index].target_si = target_si;
2088}
2089
2090bool VersionTracker::init_verneed(const soinfo* si_from) {
2091 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2092
2093 if (verneed_ptr == 0) {
2094 return true;
2095 }
2096
2097 size_t verneed_cnt = si_from->get_verneed_cnt();
2098
2099 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2100 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2101 size_t vernaux_offset = offset + verneed->vn_aux;
2102 offset += verneed->vn_next;
2103
2104 if (verneed->vn_version != 1) {
2105 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2106 return false;
2107 }
2108
2109 const char* target_soname = si_from->get_string(verneed->vn_file);
2110 // find it in dependencies
2111 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002112 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002113 });
2114
2115 if (target_si == nullptr) {
2116 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002117 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002118 return false;
2119 }
2120
2121 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2122 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2123 vernaux_offset += vernaux->vna_next;
2124
2125 const ElfW(Word) elf_hash = vernaux->vna_hash;
2126 const char* ver_name = si_from->get_string(vernaux->vna_name);
2127 ElfW(Half) source_index = vernaux->vna_other;
2128
2129 add_version_info(source_index, elf_hash, ver_name, target_si);
2130 }
2131 }
2132
2133 return true;
2134}
2135
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002136template <typename F>
2137static bool for_each_verdef(const soinfo* si, F functor) {
2138 if (!si->has_min_version(2)) {
2139 return true;
2140 }
2141
2142 uintptr_t verdef_ptr = si->get_verdef_ptr();
2143 if (verdef_ptr == 0) {
2144 return true;
2145 }
2146
2147 size_t offset = 0;
2148
2149 size_t verdef_cnt = si->get_verdef_cnt();
2150 for (size_t i = 0; i<verdef_cnt; ++i) {
2151 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2152 size_t verdaux_offset = offset + verdef->vd_aux;
2153 offset += verdef->vd_next;
2154
2155 if (verdef->vd_version != 1) {
2156 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2157 i, verdef->vd_version, si->get_realpath());
2158 return false;
2159 }
2160
2161 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2162 // "this is the version of the file itself. It must not be used for
2163 // matching a symbol. It can be used to match references."
2164 //
2165 // http://www.akkadia.org/drepper/symbol-versioning
2166 continue;
2167 }
2168
2169 if (verdef->vd_cnt == 0) {
2170 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2171 return false;
2172 }
2173
2174 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2175
2176 if (functor(i, verdef, verdaux) == true) {
2177 break;
2178 }
2179 }
2180
2181 return true;
2182}
2183
2184bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2185 if (vi == nullptr) {
2186 *versym = kVersymNotNeeded;
2187 return true;
2188 }
2189
2190 *versym = kVersymGlobal;
2191
2192 return for_each_verdef(si,
2193 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2194 if (verdef->vd_hash == vi->elf_hash &&
2195 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2196 *versym = verdef->vd_ndx;
2197 return true;
2198 }
2199
2200 return false;
2201 }
2202 );
2203}
2204
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002205bool VersionTracker::init_verdef(const soinfo* si_from) {
2206 return for_each_verdef(si_from,
2207 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2208 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2209 si_from->get_string(verdaux->vda_name), si_from);
2210 return false;
2211 }
2212 );
2213}
2214
2215bool VersionTracker::init(const soinfo* si_from) {
2216 if (!si_from->has_min_version(2)) {
2217 return true;
2218 }
2219
2220 return init_verneed(si_from) && init_verdef(si_from);
2221}
2222
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002223#if !defined(__mips__)
2224#if defined(USE_RELA)
2225static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2226 return rela->r_addend;
2227}
2228#else
2229static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2230 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2231 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2232 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2233 }
2234 return 0;
2235}
2236#endif
2237
2238// TODO (dimitry): Methods below need to be moved out of soinfo
2239// and in more isolated file in order minimize dependencies on
2240// unnecessary object in the linker binary. Consider making them
2241// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002242bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2243 const char* sym_name, const version_info** vi) {
2244 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2245 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2246
2247 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2248 *vi = version_tracker.get_version_info(sym_ver);
2249
2250 if (*vi == nullptr) {
2251 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002252 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002253 return false;
2254 }
2255 } else {
2256 // there is no version info
2257 *vi = nullptr;
2258 }
2259
2260 return true;
2261}
2262
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002263template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002264bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2265 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002266 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2267 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002268 if (rel == nullptr) {
2269 return false;
2270 }
2271
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002272 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2273 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2274
2275 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002276 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002277 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002278 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002279
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002280 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002281 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002282 continue;
2283 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002284
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002285 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002286 soinfo* lsi = nullptr;
2287
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002288 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002289 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002290 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002291
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002292 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2293 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002294 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002295
2296 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2297 return false;
2298 }
2299
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002300 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002301 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002302 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002303 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002304 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002305 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002306 }
2307
2308 /* IHI0044C AAELF 4.5.1.1:
2309
2310 Libraries are not searched to resolve weak references.
2311 It is not an error for a weak reference to remain unsatisfied.
2312
2313 During linking, the value of an undefined weak reference is:
2314 - Zero if the relocation type is absolute
2315 - The address of the place if the relocation is pc-relative
2316 - The address of nominal base address if the relocation
2317 type is base-relative.
2318 */
2319
2320 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002321 case R_GENERIC_JUMP_SLOT:
2322 case R_GENERIC_GLOB_DAT:
2323 case R_GENERIC_RELATIVE:
2324 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002325#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002326 case R_AARCH64_ABS64:
2327 case R_AARCH64_ABS32:
2328 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002329#elif defined(__x86_64__)
2330 case R_X86_64_32:
2331 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002332#elif defined(__arm__)
2333 case R_ARM_ABS32:
2334#elif defined(__i386__)
2335 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002336#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002337 /*
2338 * The sym_addr was initialized to be zero above, or the relocation
2339 * code below does not care about value of sym_addr.
2340 * No need to do anything.
2341 */
2342 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002343#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002344 case R_X86_64_PC32:
2345 sym_addr = reloc;
2346 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002347#elif defined(__i386__)
2348 case R_386_PC32:
2349 sym_addr = reloc;
2350 break;
2351#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002352 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002353 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002354 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002355 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002356 } else { // We got a definition.
2357#if !defined(__LP64__)
2358 // When relocating dso with text_relocation .text segment is
2359 // not executable. We need to restore elf flags before resolving
2360 // STT_GNU_IFUNC symbol.
2361 bool protect_segments = has_text_relocations &&
2362 lsi == this &&
2363 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2364 if (protect_segments) {
2365 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2366 DL_ERR("can't protect segments for \"%s\": %s",
2367 get_realpath(), strerror(errno));
2368 return false;
2369 }
2370 }
2371#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002372 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002373#if !defined(__LP64__)
2374 if (protect_segments) {
2375 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2376 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2377 get_realpath(), strerror(errno));
2378 return false;
2379 }
2380 }
2381#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002382 }
2383 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002384 }
2385
2386 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002387 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002388 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002389 MARK(rel->r_offset);
2390 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2391 reinterpret_cast<void*>(reloc),
2392 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2393
2394 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002395 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002396 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002397 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002398 MARK(rel->r_offset);
2399 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2400 reinterpret_cast<void*>(reloc),
2401 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2402 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002403 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002404 case R_GENERIC_RELATIVE:
2405 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002406 MARK(rel->r_offset);
2407 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2408 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002409 reinterpret_cast<void*>(load_bias + addend));
2410 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002411 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002412 case R_GENERIC_IRELATIVE:
2413 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002414 MARK(rel->r_offset);
2415 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2416 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002417 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002418 {
2419#if !defined(__LP64__)
2420 // When relocating dso with text_relocation .text segment is
2421 // not executable. We need to restore elf flags for this
2422 // particular call.
2423 if (has_text_relocations) {
2424 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2425 DL_ERR("can't protect segments for \"%s\": %s",
2426 get_realpath(), strerror(errno));
2427 return false;
2428 }
2429 }
2430#endif
2431 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2432#if !defined(__LP64__)
2433 // Unprotect it afterwards...
2434 if (has_text_relocations) {
2435 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2436 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2437 get_realpath(), strerror(errno));
2438 return false;
2439 }
2440 }
2441#endif
2442 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2443 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002444 break;
2445
2446#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002447 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002448 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002449 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002450 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002451 reloc, sym_addr + addend, sym_name);
2452 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002453 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002454 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002455 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002456 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002457 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002458 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002459 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002460 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2461 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002462 if ((min_value <= (sym_addr + addend)) &&
2463 ((sym_addr + addend) <= max_value)) {
2464 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002465 } else {
2466 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002467 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002468 return false;
2469 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002470 }
2471 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002472 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002473 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002474 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002475 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002476 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002477 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002478 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2479 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002480 if ((min_value <= (sym_addr + addend)) &&
2481 ((sym_addr + addend) <= max_value)) {
2482 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002483 } else {
2484 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002485 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002486 return false;
2487 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002488 }
2489 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002490 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002491 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002492 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002493 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002494 reloc, sym_addr + addend, rel->r_offset, sym_name);
2495 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002496 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002497 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002498 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002499 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002500 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002501 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002502 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002503 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2504 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002505 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2506 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2507 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002508 } else {
2509 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002510 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002511 return false;
2512 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002513 }
2514 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002515 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002516 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002517 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002518 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002519 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002520 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002521 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2522 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002523 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2524 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2525 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002526 } else {
2527 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002528 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002529 return false;
2530 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002531 }
2532 break;
2533
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002534 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002535 /*
2536 * ET_EXEC is not supported so this should not happen.
2537 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002538 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002539 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002540 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002541 * R_AARCH64_COPY may only appear in executable objects where e_type is
2542 * set to ET_EXEC.
2543 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002544 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002545 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002546 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002547 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002548 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002549 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002550 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002551 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002552 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002553 break;
2554#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002555 case R_X86_64_32:
2556 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002557 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002558 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2559 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002560 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002561 break;
2562 case R_X86_64_64:
2563 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002564 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002565 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2566 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002567 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002568 break;
2569 case R_X86_64_PC32:
2570 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002571 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002572 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2573 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2574 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002575 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002576 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002577#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002578 case R_ARM_ABS32:
2579 count_relocation(kRelocAbsolute);
2580 MARK(rel->r_offset);
2581 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2582 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2583 break;
2584 case R_ARM_REL32:
2585 count_relocation(kRelocRelative);
2586 MARK(rel->r_offset);
2587 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2588 reloc, sym_addr, rel->r_offset, sym_name);
2589 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2590 break;
2591 case R_ARM_COPY:
2592 /*
2593 * ET_EXEC is not supported so this should not happen.
2594 *
2595 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2596 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002597 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002598 * R_ARM_COPY may only appear in executable objects where e_type is
2599 * set to ET_EXEC.
2600 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002601 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002602 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002603#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002604 case R_386_32:
2605 count_relocation(kRelocRelative);
2606 MARK(rel->r_offset);
2607 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2608 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2609 break;
2610 case R_386_PC32:
2611 count_relocation(kRelocRelative);
2612 MARK(rel->r_offset);
2613 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2614 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2615 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2616 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002617#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002618 default:
2619 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002620 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002621 }
2622 }
2623 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002624}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002625#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002626
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002627// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002628static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002629
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002630bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002631 /* Extract dynamic section */
2632 ElfW(Word) dynamic_flags = 0;
2633 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002634
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002635 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002636 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002637 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002638 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002639 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002640 }
2641
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002642 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002643 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002644 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002645 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002646 return false;
2647 } else {
2648 if (!relocating_linker) {
2649 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002650 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002651 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002652
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002653#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002654 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2655 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002656#endif
2657
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002658 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002659 // Note that: "Except for the DT_NULL element at the end of the array,
2660 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2661 //
2662 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002663 uint32_t needed_count = 0;
2664 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2665 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2666 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2667 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002668 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002669 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002670 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002671
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002672 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002673 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2674 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2675 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2676 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002677 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002678
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002679 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002680 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002681 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002682 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2683 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002684
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002685 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002686 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002687 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002688 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2689 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002690
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002691 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002692 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002693 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002694 return false;
2695 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002696 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002697
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002698 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002699 break;
2700
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002701 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002702 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002703 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002704
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002705 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002706 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002707 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002708
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002709 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002710 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002711 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002712
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002713 case DT_SYMENT:
2714 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002715 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2716 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002717 return false;
2718 }
2719 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002720
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002721 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002722#if defined(USE_RELA)
2723 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002724 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002725 return false;
2726 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002727#else
2728 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002729 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002730 return false;
2731 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002732#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002733 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002734
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002735 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002736#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002737 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002738#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002739 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002740#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002741 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002742
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002743 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002744#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002745 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002746#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002747 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002748#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002749 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002750
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002751 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002752#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002753 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002754 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002755#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002756 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2757 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002758
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002759 case DT_DEBUG:
2760 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2761 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002762// FIXME: not working currently for N64
2763// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002764// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002765// read-only, but the DYNAMIC header claims it is writable.
2766#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002767 if ((dynamic_flags & PF_W) != 0) {
2768 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2769 }
Chris Dearman99186652014-02-06 20:36:51 -08002770#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002771 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002772#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002773 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002774 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002775 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002776
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002777 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002778 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002779 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002780
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002781 case DT_ANDROID_RELA:
2782 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2783 break;
2784
2785 case DT_ANDROID_RELASZ:
2786 android_relocs_size_ = d->d_un.d_val;
2787 break;
2788
2789 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002790 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002791 return false;
2792
2793 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002794 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002795 return false;
2796
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002797 case DT_RELAENT:
2798 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002799 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002800 return false;
2801 }
2802 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002803
2804 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002805 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002806 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002807
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002808 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002809 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002810 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002811
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002812 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002813 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002814 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002815
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002816#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002817 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002818 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002819 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002820
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002821 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002822 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002823 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002824
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002825 case DT_RELENT:
2826 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002827 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002828 return false;
2829 }
2830 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002831
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002832 case DT_ANDROID_REL:
2833 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2834 break;
2835
2836 case DT_ANDROID_RELSZ:
2837 android_relocs_size_ = d->d_un.d_val;
2838 break;
2839
2840 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002841 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002842 return false;
2843
2844 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002845 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002846 return false;
2847
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002848 // "Indicates that all RELATIVE relocations have been concatenated together,
2849 // and specifies the RELATIVE relocation count."
2850 //
2851 // TODO: Spec also mentions that this can be used to optimize relocation process;
2852 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002853 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002854 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002855
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002856 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002857 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002858 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002859
2860 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002861 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002862 return false;
2863
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002864#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002865 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002866 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002867 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002868 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002869
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002870 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002871 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002872 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002873 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002874
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002875 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002876 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002877 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002878 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002879
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002880 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002881 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002882 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002883
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002884 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002885 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002886 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002887 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002888
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002889 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002890 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002891 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002892
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002893 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002894 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002895 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002896 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002897
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002898 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002899 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002900 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002901
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002902 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002903#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002904 DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002905 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002906#else
2907 has_text_relocations = true;
2908 break;
2909#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002910
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002911 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002912 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002913 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002914
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002915 case DT_NEEDED:
2916 ++needed_count;
2917 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002918
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002919 case DT_FLAGS:
2920 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002921#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002922 DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002923 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002924#else
2925 has_text_relocations = true;
2926#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002927 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002928 if (d->d_un.d_val & DF_SYMBOLIC) {
2929 has_DT_SYMBOLIC = true;
2930 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002931 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002932
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002933 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002934 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002935
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002936 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dmitriy Ivanov087005f2015-05-28 11:44:31 -07002937 DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002938 }
2939 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002940#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002941 case DT_MIPS_RLD_MAP:
2942 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
2943 {
2944 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
2945 *dp = &_r_debug;
2946 }
2947 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02002948 case DT_MIPS_RLD_MAP_REL:
2949 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08002950 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002951 r_debug** dp = reinterpret_cast<r_debug**>(
2952 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08002953 *dp = &_r_debug;
2954 }
2955 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002956
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002957 case DT_MIPS_RLD_VERSION:
2958 case DT_MIPS_FLAGS:
2959 case DT_MIPS_BASE_ADDRESS:
2960 case DT_MIPS_UNREFEXTNO:
2961 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002962
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002963 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002964 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002965 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002966
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002967 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002968 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002969 break;
2970
2971 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002972 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002973 break;
2974#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002975 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2976 case DT_BIND_NOW:
2977 break;
2978
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002979 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002980 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
2981 break;
2982
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002983 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002984 verdef_ptr_ = load_bias + d->d_un.d_ptr;
2985 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002986 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002987 verdef_cnt_ = d->d_un.d_val;
2988 break;
2989
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002990 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002991 verneed_ptr_ = load_bias + d->d_un.d_ptr;
2992 break;
2993
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002994 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002995 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002996 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002997
Evgenii Stepanov68650822015-06-10 13:38:39 -07002998 case DT_RUNPATH:
2999 // this is parsed after we have strtab initialized (see below).
3000 break;
3001
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003002 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003003 if (!relocating_linker) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003004 DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003005 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3006 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003007 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003008 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003009 }
3010
Duane Sandbc425c72015-06-01 16:29:14 -07003011#if defined(__mips__) && !defined(__LP64__)
3012 if (!mips_check_and_adjust_fp_modes()) {
3013 return false;
3014 }
3015#endif
3016
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003017 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003018 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003019
3020 // Sanity checks.
3021 if (relocating_linker && needed_count != 0) {
3022 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3023 return false;
3024 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003025 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003026 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003027 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003028 return false;
3029 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003030 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003031 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003032 return false;
3033 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003034 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003035 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003036 return false;
3037 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003038
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003039 // second pass - parse entries relying on strtab
3040 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003041 switch (d->d_tag) {
3042 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003043 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003044 break;
3045 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003046 set_dt_runpath(get_string(d->d_un.d_val));
3047 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003048 }
3049 }
3050
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003051 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003052 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003053 // because they can't find dt_needed library by soname.
3054 // This workaround should keep them working. (applies only
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003055 // for apps targeting sdk version <=22). Make an exception for
3056 // the main executable and linker; they do not need to have dt_soname
3057 if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
3058 get_application_target_sdk_version() <= 22) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003059 soname_ = basename(realpath_.c_str());
3060 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3061 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003062 // Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003063 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003064 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003065}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003066
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003067bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3068 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003069
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003070 local_group_root_ = local_group.front();
3071 if (local_group_root_ == nullptr) {
3072 local_group_root_ = this;
3073 }
3074
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003075 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3076 target_sdk_version_ = get_application_target_sdk_version();
3077 }
3078
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003079 VersionTracker version_tracker;
3080
3081 if (!version_tracker.init(this)) {
3082 return false;
3083 }
3084
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003085#if !defined(__LP64__)
3086 if (has_text_relocations) {
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003087 // Fail if app is targeting sdk version > 22
Dmitriy Ivanov80687862015-10-09 13:58:46 -07003088 if (get_application_target_sdk_version() > 22) {
Dmitriy Ivanovfae39d22015-10-13 11:07:56 -07003089 PRINT("%s: has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003090 DL_ERR("%s: has text relocations", get_realpath());
3091 return false;
3092 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003093 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003094 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003095 DL_WARN("%s has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003096 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003097 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003098 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3099 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003100 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003101 return false;
3102 }
3103 }
3104#endif
3105
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003106 if (android_relocs_ != nullptr) {
3107 // check signature
3108 if (android_relocs_size_ > 3 &&
3109 android_relocs_[0] == 'A' &&
3110 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003111 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003112 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003113 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003114
3115 bool relocated = false;
3116 const uint8_t* packed_relocs = android_relocs_ + 4;
3117 const size_t packed_relocs_size = android_relocs_size_ - 4;
3118
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003119 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003120 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003121 packed_reloc_iterator<sleb128_decoder>(
3122 sleb128_decoder(packed_relocs, packed_relocs_size)),
3123 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003124
3125 if (!relocated) {
3126 return false;
3127 }
3128 } else {
3129 DL_ERR("bad android relocation header.");
3130 return false;
3131 }
3132 }
3133
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003134#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003135 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003136 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003137 if (!relocate(version_tracker,
3138 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003139 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003140 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003141 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003142 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003143 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003144 if (!relocate(version_tracker,
3145 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003146 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003147 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003148 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003149#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003150 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003151 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003152 if (!relocate(version_tracker,
3153 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003154 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003155 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003156 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003157 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003158 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003159 if (!relocate(version_tracker,
3160 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003161 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003162 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003163 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003164#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003165
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003166#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003167 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003168 return false;
3169 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003170#endif
3171
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003172 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003173
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003174#if !defined(__LP64__)
3175 if (has_text_relocations) {
3176 // All relocations are done, we can protect our segments back to read-only.
3177 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3178 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003179 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003180 return false;
3181 }
3182 }
3183#endif
3184
Mingwei Shibe910522015-11-12 07:02:14 +00003185 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3186 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3187 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003188 return false;
3189 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003190
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003191 /* Handle serializing/sharing the RELRO segment */
3192 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3193 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3194 extinfo->relro_fd) < 0) {
3195 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003196 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003197 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003198 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003199 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3200 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3201 extinfo->relro_fd) < 0) {
3202 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003203 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003204 return false;
3205 }
3206 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003207
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003208 notify_gdb_of_load(this);
3209 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003210}
3211
Mingwei Shibe910522015-11-12 07:02:14 +00003212bool soinfo::protect_relro() {
3213 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3214 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3215 get_realpath(), strerror(errno));
3216 return false;
3217 }
3218 return true;
3219}
3220
Nick Kralevich468319c2011-11-11 15:53:17 -08003221/*
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003222 * This function add vdso to internal dso list.
3223 * It helps to stack unwinding through signal handlers.
3224 * Also, it makes bionic more like glibc.
3225 */
Kito Cheng812fd422014-03-25 22:53:56 +08003226static void add_vdso(KernelArgumentBlock& args __unused) {
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003227#if defined(AT_SYSINFO_EHDR)
Elliott Hughes0266ae52014-02-10 17:46:57 -08003228 ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07003229 if (ehdr_vdso == nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -08003230 return;
3231 }
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003232
Dmitriy Ivanovd9b08a02015-11-16 13:17:27 -08003233 soinfo* si = soinfo_alloc(&g_default_namespace, "[vdso]", nullptr, 0, 0);
Sergey Melnikovebd506c2013-10-31 18:02:12 +04003234
Elliott Hughes0266ae52014-02-10 17:46:57 -08003235 si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
3236 si->phnum = ehdr_vdso->e_phnum;
3237 si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
3238 si->size = phdr_table_get_load_size(si->phdr, si->phnum);
Elliott Hughes0266ae52014-02-10 17:46:57 -08003239 si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
Sergey Melnikovebd506c2013-10-31 18:02:12 +04003240
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003241 si->prelink_image();
Dimitry Ivanovb943f302016-08-03 16:00:10 -07003242 si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr);
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003243#endif
3244}
3245
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003246/* gdb expects the linker to be in the debug shared object list.
3247 * Without this, gdb has trouble locating the linker's ".text"
3248 * and ".plt" sections. Gdb could also potentially use this to
3249 * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
Dimitry Ivanov64001292016-02-17 14:13:06 -08003250 * Note that the linker shouldn't be on the soinfo list.
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003251 */
3252static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
Dimitry Ivanov8d22dd52016-02-16 13:43:35 -08003253 static link_map linker_link_map_for_gdb;
3254#if defined(__LP64__)
3255 static char kLinkerPath[] = "/system/bin/linker64";
3256#else
3257 static char kLinkerPath[] = "/system/bin/linker";
3258#endif
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003259
Dimitry Ivanov8d22dd52016-02-16 13:43:35 -08003260 linker_link_map_for_gdb.l_addr = linker_base;
3261 linker_link_map_for_gdb.l_name = kLinkerPath;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003262
3263 /*
3264 * Set the dynamic field in the link map otherwise gdb will complain with
3265 * the following:
3266 * warning: .dynamic section for "/system/bin/linker" is not at the
3267 * expected address (wrong library or version mismatch?)
3268 */
3269 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
3270 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
3271 phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
Dimitry Ivanov8d22dd52016-02-16 13:43:35 -08003272 &linker_link_map_for_gdb.l_ld, nullptr);
3273
3274 insert_link_map_into_debug_map(&linker_link_map_for_gdb);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003275}
3276
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003277static void init_default_namespace() {
3278 g_default_namespace.set_name("(default)");
3279 g_default_namespace.set_isolated(false);
3280
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003281 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3282 somain->load_bias);
3283 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003284 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003285 g_default_ld_paths = kAsanDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003286 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003287 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003288 }
3289
3290 std::vector<std::string> ld_default_paths;
3291 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
3292 ld_default_paths.push_back(g_default_ld_paths[i]);
3293 }
3294
3295 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003296};
3297
Dmitriy Ivanovb4e50672015-04-28 15:49:26 -07003298extern "C" int __system_properties_init(void);
3299
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003300static const char* get_executable_path() {
3301 static std::string executable_path;
3302 if (executable_path.empty()) {
3303 char path[PATH_MAX];
3304 ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
3305 if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
3306 __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
3307 }
3308 executable_path = std::string(path, path_len);
3309 }
3310
3311 return executable_path.c_str();
3312}
3313
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003314/*
Nick Kralevich468319c2011-11-11 15:53:17 -08003315 * This code is called after the linker has linked itself and
3316 * fixed it's own GOT. It is safe to make references to externs
3317 * and other non-local data at this point.
3318 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08003319static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
Evgeniy Stepanov1a78fbb2012-03-22 18:01:53 +04003320#if TIMING
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003321 struct timeval t0, t1;
3322 gettimeofday(&t0, 0);
Evgeniy Stepanov1a78fbb2012-03-22 18:01:53 +04003323#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003324
Elliott Hughes1801db32015-06-08 18:04:00 -07003325 // Sanitize the environment.
3326 __libc_init_AT_SECURE(args);
David 'Digit' Turnerbe575592010-12-16 19:52:02 +01003327
Dmitriy Ivanovb4e50672015-04-28 15:49:26 -07003328 // Initialize system properties
3329 __system_properties_init(); // may use 'environ'
3330
Josh Gao3cc387e2016-06-15 18:33:26 -07003331 // Register the debuggerd signal handler.
3332 debuggerd_callbacks_t callbacks = {
3333 .get_abort_message = []() {
3334 return g_abort_message;
3335 },
3336 .post_dump = &notify_gdb_of_libraries,
3337 };
3338 debuggerd_init(&callbacks);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003339
Dimitry Ivanovb996d602016-07-11 18:11:39 -07003340 g_linker_logger.ResetState();
3341
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003342 // Get a few environment variables.
Elliott Hughes1801db32015-06-08 18:04:00 -07003343 const char* LD_DEBUG = getenv("LD_DEBUG");
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003344 if (LD_DEBUG != nullptr) {
3345 g_ld_debug_verbosity = atoi(LD_DEBUG);
3346 }
3347
Elliott Hughes116b5692016-01-04 17:45:36 -08003348#if defined(__LP64__)
3349 INFO("[ Android dynamic linker (64-bit) ]");
3350#else
3351 INFO("[ Android dynamic linker (32-bit) ]");
3352#endif
3353
Elliott Hughes1801db32015-06-08 18:04:00 -07003354 // These should have been sanitized by __libc_init_AT_SECURE, but the test
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003355 // doesn't cost us anything.
3356 const char* ldpath_env = nullptr;
3357 const char* ldpreload_env = nullptr;
Elliott Hughes1801db32015-06-08 18:04:00 -07003358 if (!getauxval(AT_SECURE)) {
3359 ldpath_env = getenv("LD_LIBRARY_PATH");
Elliott Hughes116b5692016-01-04 17:45:36 -08003360 if (ldpath_env != nullptr) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003361 INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env);
Elliott Hughes116b5692016-01-04 17:45:36 -08003362 }
Elliott Hughes1801db32015-06-08 18:04:00 -07003363 ldpreload_env = getenv("LD_PRELOAD");
Elliott Hughes116b5692016-01-04 17:45:36 -08003364 if (ldpreload_env != nullptr) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003365 INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env);
Elliott Hughes116b5692016-01-04 17:45:36 -08003366 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003367 }
3368
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003369 const char* executable_path = get_executable_path();
3370 struct stat file_stat;
3371 if (TEMP_FAILURE_RETRY(stat(executable_path, &file_stat)) != 0) {
3372 __libc_fatal("unable to stat file for the executable \"%s\": %s", executable_path, strerror(errno));
3373 }
3374
3375 soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003376 if (si == nullptr) {
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003377 __libc_fatal("Couldn't allocate soinfo: out of memory?");
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003378 }
3379
3380 /* bootstrap the link map, the main exe always needs to be first */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003381 si->set_main_executable();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003382 link_map* map = &(si->link_map_head);
3383
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -08003384 // Register the main executable and the linker upfront to have
3385 // gdb aware of them before loading the rest of the dependency
3386 // tree.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003387 map->l_addr = 0;
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003388 map->l_name = const_cast<char*>(executable_path);
Dimitry Ivanovf3064e42016-02-17 15:25:25 -08003389 insert_link_map_into_debug_map(map);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003390 init_linker_info_for_gdb(linker_base);
3391
3392 // Extract information passed from the kernel.
3393 si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
3394 si->phnum = args.getauxval(AT_PHNUM);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003395
3396 /* Compute the value of si->base. We can't rely on the fact that
3397 * the first entry is the PHDR because this will not be true
3398 * for certain executables (e.g. some in the NDK unit test suite)
3399 */
3400 si->base = 0;
3401 si->size = phdr_table_get_load_size(si->phdr, si->phnum);
3402 si->load_bias = 0;
3403 for (size_t i = 0; i < si->phnum; ++i) {
3404 if (si->phdr[i].p_type == PT_PHDR) {
3405 si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
3406 si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
3407 break;
Nick Kralevich8d3e91d2013-04-25 13:15:24 -07003408 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003409 }
3410 si->dynamic = nullptr;
Nick Kralevich8d3e91d2013-04-25 13:15:24 -07003411
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003412 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
3413 if (elf_hdr->e_type != ET_DYN) {
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003414 __libc_fatal("\"%s\": error: only position independent executables (PIE) are supported.",
Dimitry Ivanov55437462016-07-20 15:33:07 -07003415 g_argv[0]);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003416 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003417
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003418 // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
3419 parse_LD_LIBRARY_PATH(ldpath_env);
3420 parse_LD_PRELOAD(ldpreload_env);
David 'Digit' Turnerbe575592010-12-16 19:52:02 +01003421
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003422 somain = si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003423
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003424 init_default_namespace();
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003425
Dmitriy Ivanov67181252015-01-07 15:48:25 -08003426 if (!si->prelink_image()) {
Dimitry Ivanov55437462016-07-20 15:33:07 -07003427 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
Dmitriy Ivanov67181252015-01-07 15:48:25 -08003428 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003429
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003430 // add somain to global group
3431 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
3432
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003433 // Load ld_preloads and dependencies.
3434 StringLinkedList needed_library_name_list;
3435 size_t needed_libraries_count = 0;
3436 size_t ld_preloads_count = 0;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07003437
3438 for (const auto& ld_preload_name : g_ld_preload_names) {
3439 needed_library_name_list.push_back(ld_preload_name.c_str());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003440 ++needed_libraries_count;
Dmitriy Ivanovf8093a92015-04-28 18:09:53 -07003441 ++ld_preloads_count;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003442 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003443
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003444 for_each_dt_needed(si, [&](const char* name) {
3445 needed_library_name_list.push_back(name);
3446 ++needed_libraries_count;
3447 });
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003448
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003449 const char* needed_library_names[needed_libraries_count];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003450
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003451 memset(needed_library_names, 0, sizeof(needed_library_names));
3452 needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003453
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07003454 if (needed_libraries_count > 0 &&
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003455 !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
3456 nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07003457 /* add_as_children */ true)) {
Dimitry Ivanov55437462016-07-20 15:33:07 -07003458 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003459 } else if (needed_libraries_count == 0) {
Dimitry Ivanovb943f302016-08-03 16:00:10 -07003460 if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
Dimitry Ivanov55437462016-07-20 15:33:07 -07003461 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003462 }
3463 si->increment_ref_count();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003464 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003465
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003466 add_vdso(args);
Nick Kralevich2aebf542014-05-07 10:32:39 -07003467
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08003468 {
3469 ProtectedDataGuard guard;
Matt Fischer4fd42c12009-12-31 12:09:10 -06003470
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08003471 si->call_pre_init_constructors();
3472
3473 /* After the prelink_image, the si->load_bias is initialized.
3474 * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
3475 * We need to update this value for so exe here. So Unwind_Backtrace
3476 * for some arch like x86 could work correctly within so exe.
3477 */
3478 map->l_addr = si->load_bias;
3479 si->call_constructors();
3480 }
Evgeniy Stepanove83c56d2011-12-21 13:03:54 +04003481
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003482#if TIMING
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003483 gettimeofday(&t1, nullptr);
Dimitry Ivanov55437462016-07-20 15:33:07 -07003484 PRINT("LINKER TIME: %s: %d microseconds", g_argv[0], (int) (
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003485 (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
3486 (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003487#endif
3488#if STATS
Dimitry Ivanov55437462016-07-20 15:33:07 -07003489 PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", g_argv[0],
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003490 linker_stats.count[kRelocAbsolute],
3491 linker_stats.count[kRelocRelative],
3492 linker_stats.count[kRelocCopy],
3493 linker_stats.count[kRelocSymbol]);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003494#endif
3495#if COUNT_PAGES
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003496 {
3497 unsigned n;
3498 unsigned i;
3499 unsigned count = 0;
3500 for (n = 0; n < 4096; n++) {
3501 if (bitmask[n]) {
3502 unsigned x = bitmask[n];
Marcus Oaklande365f9d2013-10-10 15:19:31 +01003503#if defined(__LP64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003504 for (i = 0; i < 32; i++) {
Marcus Oaklande365f9d2013-10-10 15:19:31 +01003505#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003506 for (i = 0; i < 8; i++) {
Marcus Oaklande365f9d2013-10-10 15:19:31 +01003507#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003508 if (x & 1) {
3509 count++;
3510 }
3511 x >>= 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003512 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003513 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003514 }
Dimitry Ivanov55437462016-07-20 15:33:07 -07003515 PRINT("PAGES MODIFIED: %s: %d (%dKB)", g_argv[0], count, count * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003516 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003517#endif
3518
3519#if TIMING || STATS || COUNT_PAGES
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003520 fflush(stdout);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003521#endif
3522
Dimitry Ivanove687d062016-02-16 13:25:29 -08003523 ElfW(Addr) entry = args.getauxval(AT_ENTRY);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003524 TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
Dimitry Ivanove687d062016-02-16 13:25:29 -08003525 return entry;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003526}
Nick Kralevich468319c2011-11-11 15:53:17 -08003527
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003528/* Compute the load-bias of an existing executable. This shall only
3529 * be used to compute the load bias of an executable or shared library
3530 * that was loaded by the kernel itself.
3531 *
3532 * Input:
3533 * elf -> address of ELF header, assumed to be at the start of the file.
3534 * Return:
3535 * load bias, i.e. add the value of any p_vaddr in the file to get
3536 * the corresponding address in memory.
3537 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08003538static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
3539 ElfW(Addr) offset = elf->e_phoff;
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003540 const ElfW(Phdr)* phdr_table =
3541 reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08003542 const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003543
Elliott Hughes0266ae52014-02-10 17:46:57 -08003544 for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
Kito Chengfa8c05d2013-03-12 14:58:06 +08003545 if (phdr->p_type == PT_LOAD) {
Elliott Hughes0266ae52014-02-10 17:46:57 -08003546 return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003547 }
Kito Chengfa8c05d2013-03-12 14:58:06 +08003548 }
3549 return 0;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003550}
3551
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003552static void __linker_cannot_link(const char* argv0) {
3553 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
Mingwei Shibe910522015-11-12 07:02:14 +00003554}
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003555
Nick Kralevich468319c2011-11-11 15:53:17 -08003556/*
3557 * This is the entry point for the linker, called from begin.S. This
3558 * method is responsible for fixing the linker's own relocations, and
3559 * then calling __linker_init_post_relocation().
3560 *
3561 * Because this method is called before the linker has fixed it's own
3562 * relocations, any attempt to reference an extern variable, extern
3563 * function, or other GOT reference will generate a segfault.
3564 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08003565extern "C" ElfW(Addr) __linker_init(void* raw_args) {
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003566 KernelArgumentBlock args(raw_args);
Nick Kralevich468319c2011-11-11 15:53:17 -08003567
Elliott Hughes0266ae52014-02-10 17:46:57 -08003568 ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003569 ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
Elliott Hughes0266ae52014-02-10 17:46:57 -08003570 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
Elliott Hughesfaf05ba2014-02-11 16:59:37 -08003571 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
Nick Kralevich468319c2011-11-11 15:53:17 -08003572
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003573 soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
Nick Kralevich468319c2011-11-11 15:53:17 -08003574
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003575 // If the linker is not acting as PT_INTERP entry_point is equal to
3576 // _start. Which means that the linker is running as an executable and
3577 // already linked by PT_INTERP.
3578 //
3579 // This happens when user tries to run 'adb shell /system/bin/linker'
3580 // see also https://code.google.com/p/android/issues/detail?id=63174
3581 if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003582 __libc_format_fd(STDOUT_FILENO,
3583 "This is %s, the helper program for shared library executables.\n",
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003584 args.argv[0]);
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003585 exit(0);
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003586 }
3587
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003588 linker_so.base = linker_addr;
3589 linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
3590 linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07003591 linker_so.dynamic = nullptr;
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003592 linker_so.phdr = phdr;
3593 linker_so.phnum = elf_hdr->e_phnum;
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003594 linker_so.set_linker_flag();
Elliott Hughes5419b942012-10-16 15:54:46 -07003595
Mingwei Shibe910522015-11-12 07:02:14 +00003596 // Prelink the linker so we can access linker globals.
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003597 if (!linker_so.prelink_image()) __linker_cannot_link(args.argv[0]);
Mingwei Shibe910522015-11-12 07:02:14 +00003598
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003599 // This might not be obvious... The reasons why we pass g_empty_list
3600 // in place of local_group here are (1) we do not really need it, because
3601 // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
3602 // itself without having to look into local_group and (2) allocators
3603 // are not yet initialized, and therefore we cannot use linked_list.push_*
3604 // functions at this point.
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003605 if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args.argv[0]);
Elliott Hughesd23736e2012-11-01 15:16:56 -07003606
Mingwei Shibe910522015-11-12 07:02:14 +00003607#if defined(__i386__)
3608 // On x86, we can't make system calls before this point.
3609 // We can't move this up because this needs to assign to a global.
3610 // Note that until we call __libc_init_main_thread below we have
3611 // no TLS, so you shouldn't make a system call that can fail, because
3612 // it will SEGV when it tries to set errno.
3613 __libc_init_sysinfo(args);
3614#endif
3615
3616 // Initialize the main thread (including TLS, so system calls really work).
Elliott Hughesd2948632015-07-21 11:57:09 -07003617 __libc_init_main_thread(args);
Dmitriy Ivanov14241402014-08-26 14:16:52 -07003618
Mingwei Shibe910522015-11-12 07:02:14 +00003619 // We didn't protect the linker's RELRO pages in link_image because we
3620 // couldn't make system calls on x86 at that point, but we can now...
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003621 if (!linker_so.protect_relro()) __linker_cannot_link(args.argv[0]);
Mingwei Shibe910522015-11-12 07:02:14 +00003622
Josh Gao93c0f5e2015-10-06 11:08:13 -07003623 // Initialize the linker's static libc's globals
3624 __libc_init_globals(args);
3625
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003626 // store argc/argv/envp to use them for calling constructors
3627 g_argc = args.argc;
3628 g_argv = args.argv;
3629 g_envp = args.envp;
3630
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003631 // Initialize the linker's own global variables
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003632 linker_so.call_constructors();
Dmitriy Ivanov4151ea72014-07-24 15:33:25 -07003633
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003634 // Initialize static variables. Note that in order to
3635 // get correct libdl_info we need to call constructors
3636 // before get_libdl_info().
3637 solist = get_libdl_info();
3638 sonext = get_libdl_info();
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07003639 g_default_namespace.add_soinfo(get_libdl_info());
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003640
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003641 // We have successfully fixed our own relocations. It's safe to run
3642 // the main part of the linker now.
Elliott Hughes1728b232014-05-14 10:02:03 -07003643 args.abort_message_ptr = &g_abort_message;
Elliott Hughes0266ae52014-02-10 17:46:57 -08003644 ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003645
Elliott Hughes116b5692016-01-04 17:45:36 -08003646 INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
Elliott Hughes611f9562015-01-23 10:43:58 -08003647
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003648 // Return the address that the calling assembly stub should jump to.
3649 return start_address;
Nick Kralevich468319c2011-11-11 15:53:17 -08003650}