linker.cpp revision f240aa8089ea1574a7d799720efb66528f6ceb99
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
2943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan * Copyright (C) 2008, 2009 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions of source code must retain the above copyright
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions in binary form must reproduce the above copyright
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    the documentation and/or other materials provided with the
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    distribution.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
294688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <dlfcn.h>
304688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <errno.h>
314688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <fcntl.h>
320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <inttypes.h>
334688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <pthread.h>
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
374688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <sys/mman.h>
384688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h>
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
400d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new>
410d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
424688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers.
43eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h"
44eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h"
45eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h"
4604dc91ae763adc403a14c88b4c46f77b3d2d71a3Dmitriy Ivanov#include "private/ScopedFd.h"
4714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/ScopeGuard.h"
4814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/UniquePtr.h"
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h"
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h"
52be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner#include "linker_environ.h"
5323363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h"
54d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include "linker_allocator.h"
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here.
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past.
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo:
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   and NOEXEC
694688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes */
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
71489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#if defined(__LP64__)
72489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#define SEARCH_NAME(x) x
73489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#else
74489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// Nvidia drivers are relying on the bug:
75489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// http://code.google.com/p/android/issues/detail?id=6670
76489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// so we continue to use base-name lookup for lp32
77489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanovstatic const char* get_base_name(const char* name) {
78489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  const char* bname = strrchr(name, '/');
79489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  return bname ? bname + 1 : name;
80489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov}
81489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#define SEARCH_NAME(x) get_base_name(x)
82489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#endif
83489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov
840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
861728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic LinkerAllocator<soinfo> g_soinfo_allocator;
87d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic LinkerAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
88ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
89d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist;
90d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext;
916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
931728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = {
944eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__)
95011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/vendor/lib64",
96011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/system/lib64",
97011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else
98124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/vendor/lib",
99124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/system/lib",
100011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif
101851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  nullptr
102124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes};
103124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
104a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPATH_BUFSIZE (LDPATH_MAX*64)
105a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPATH_MAX 8
106a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
107a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPRELOAD_BUFSIZE (LDPRELOAD_MAX*64)
108a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPRELOAD_MAX 8
109a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
1101728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic char g_ld_library_paths_buffer[LDPATH_BUFSIZE];
1111728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* g_ld_library_paths[LDPATH_MAX + 1];
112bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1131728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic char g_ld_preloads_buffer[LDPRELOAD_BUFSIZE];
1141728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* g_ld_preload_names[LDPRELOAD_MAX + 1];
1154fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
1161728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic soinfo* g_ld_preloads[LDPRELOAD_MAX + 1];
1174fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
1181728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity;
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
120851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
1210d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes
122bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesenum RelocationKind {
1236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocAbsolute = 0,
1246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocRelative,
1256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocCopy,
1266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocSymbol,
1276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocMax
128bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes};
129be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
131bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t {
1326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int count[kRelocMax];
133bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes};
134bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
135bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats;
136bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
137bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void count_relocation(RelocationKind kind) {
1386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ++linker_stats.count[kind];
139bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
140bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else
141bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void count_relocation(RelocationKind) {
142bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
146bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic unsigned bitmask[4096];
147e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__)
148e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#define MARK(offset) \
149e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland    do { \
1506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if ((((offset) >> 12) >> 5) < 4096) \
1516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \
152faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes    } while (0)
153e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else
154bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#define MARK(offset) \
155bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes    do { \
1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
157faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes    } while (0)
158e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif
159bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else
160bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#define MARK(x) do {} while (0)
1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1634688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// You shouldn't try to call memory-allocating functions in the dynamic linker.
1644688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Guard against the most obvious ones.
1658f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#define DISALLOW_ALLOCATION(return_type, name, ...) \
1668f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes    return_type name __VA_ARGS__ \
1678f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes    { \
1686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      __libc_fatal("ERROR: " #name " called from the dynamic linker!\n"); \
1694688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes    }
170812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, malloc, (size_t u __unused));
171812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void, free, (void* u __unused));
172812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, realloc, (void* u1 __unused, size_t u2 __unused));
173812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, calloc, (size_t u1 __unused, size_t u2 __unused));
1742e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1752e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1762e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
177650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() {
1785419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return &__linker_dl_err_buf[0];
1792e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1802e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
181650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() {
182650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes  return sizeof(__linker_dl_err_buf);
183650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes}
184650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes
1856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified
1866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity.
1875419b9474753d25dff947c7740532f86d130c0beElliott Hughesextern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
1881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1891728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
190851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanovstatic r_debug _r_debug = {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
1913a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0;
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1933a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) {
1946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Copy the necessary fields into the debug structure.
1956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = info->load_bias;
1976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_name = reinterpret_cast<char*>(info->name);
1986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_ld = info->dynamic;
1996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
2006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Stick the new library at the end of the list.
2016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // gdb tends to care more about libc than it does
2026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // about leaf libraries, and ordering it this way
2036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // reduces the back-and-forth over the wire.
2046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail) {
2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail->l_next = map;
2066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = r_debug_tail;
2076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
2086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
2096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    _r_debug.r_map = map;
2106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = 0;
2116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
2126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
2141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
216bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) {
2176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
2185e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail == map) {
2206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail = map->l_prev;
2216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2225e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_prev) {
2246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev->l_next = map->l_next;
2256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_next) {
2276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next->l_prev = map->l_prev;
2286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2295e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2305e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
231bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) {
2326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (info->flags & FLAG_EXE) {
2336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
2346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_ADD;
2406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  insert_soinfo_into_debug_map(info);
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2465e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2475e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
248bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) {
2496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (info->flags & FLAG_EXE) {
2506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
2516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2535e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2555e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_DELETE;
2576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2585e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  remove_soinfo_from_debug_map(info);
2605e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26518a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() {
2663a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_ADD;
2673a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2683a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_CONSISTENT;
2693a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
272d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
273d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  return g_soinfo_links_allocator.alloc();
274d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
275d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
276d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
277d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_links_allocator.free(entry);
278d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
279d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
280d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void protect_data(int protection) {
281d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_allocator.protect_all(protection);
282d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_links_allocator.protect_all(protection);
283d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
284d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
285e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat, int rtld_flags) {
286ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  if (strlen(name) >= SOINFO_NAME_LEN) {
287ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn    DL_ERR("library name \"%s\" too long", name);
288851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
289ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  }
290ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
291e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, rtld_flags);
292d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
293ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext->next = si;
294ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext = si;
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
296ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("name %s: allocated soinfo @ %p", name, si);
297ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  return si;
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
300faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) {
3016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
3026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
3036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3044688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si->base != 0 && si->size != 0) {
3066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    munmap(reinterpret_cast<void*>(si->base), si->size);
3076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
308d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  soinfo *prev = nullptr, *trav;
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  TRACE("name %s: freeing soinfo @ %p", si->name, si);
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (trav = solist; trav != nullptr; trav = trav->next) {
3146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (trav == si) {
3156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    prev = trav;
3186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (trav == nullptr) {
3206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // si was not in solist
3216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("name \"%s\" is not in solist!", si->name);
3226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
3236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // clear links to/from si
3266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->remove_all_links();
327d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // prev will never be null, because the first entry in solist is
3296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // always the static libdl_info.
3306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  prev->next = si->next;
3316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == sonext) {
3326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    sonext = prev;
3336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
334d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
3356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  g_soinfo_allocator.free(si);
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
338cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
339cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_path(const char* path, const char* delimiters,
340cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes                       const char** array, char* buf, size_t buf_size, size_t max_count) {
341851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (path == nullptr) {
342cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    return;
343cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
344cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
345cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  size_t len = strlcpy(buf, path, buf_size);
346cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
347cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  size_t i = 0;
348cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  char* buf_p = buf;
349cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
350cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    if (*array[i] != '\0') {
351cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      ++i;
352cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    }
353cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
354cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
355cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // Forget the last path if we had to truncate; this occurs if the 2nd to
356cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // last char isn't '\0' (i.e. wasn't originally a delimiter).
357cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
358851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    array[i - 1] = nullptr;
359cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  } else {
360851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    array[i] = nullptr;
361cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
362cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
363cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
364cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_LIBRARY_PATH(const char* path) {
3651728b2396591853345507a063ed6075dfd251706Elliott Hughes  parse_path(path, ":", g_ld_library_paths,
3661728b2396591853345507a063ed6075dfd251706Elliott Hughes             g_ld_library_paths_buffer, sizeof(g_ld_library_paths_buffer), LDPATH_MAX);
367cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
368cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
369cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_PRELOAD(const char* path) {
370cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // We have historically supported ':' as well as ' ' in LD_PRELOAD.
3711728b2396591853345507a063ed6075dfd251706Elliott Hughes  parse_path(path, " :", g_ld_preload_names,
3721728b2396591853345507a063ed6075dfd251706Elliott Hughes             g_ld_preloads_buffer, sizeof(g_ld_preloads_buffer), LDPRELOAD_MAX);
373cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
374cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
3754eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
3764688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// For a given PC, find the .so that it belongs to.
3786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Returns the base address of the .ARM.exidx section
3796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// for that .so, and the number of 8-byte entries
3806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// in that section (via *pcount).
3816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Intended to be called by libc's __gnu_Unwind_Find_exidx().
3836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is exposed via dlfcn.cpp and libdl.so.
385faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
3866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  unsigned addr = (unsigned)pc;
3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != 0; si = si->next) {
3896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if ((addr >= si->base) && (addr < (si->base + si->size))) {
3906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *pcount = si->ARM_exidx_count;
3916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return (_Unwind_Ptr)si->ARM_exidx;
3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  *pcount = 0;
3956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return nullptr;
3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3974688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
39824053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif
3994688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
4006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Here, we only have to provide a callback to iterate across all the
4016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// loaded libraries. gcc_eh does the rest.
402faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesint dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
4036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int rv = 0;
4046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
4056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_phdr_info dl_info;
4066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_addr = si->link_map_head.l_addr;
4076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_name = si->link_map_head.l_name;
4086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phdr = si->phdr;
4096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phnum = si->phnum;
4106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    rv = cb(&dl_info, sizeof(dl_phdr_info), data);
4116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (rv != 0) {
4126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
4156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return rv;
4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4174688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
41802aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanovstatic ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
4190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Sym)* symtab = si->symtab;
4200266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  const char* strtab = si->strtab;
4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd",
4230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes             name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
4260266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    ElfW(Sym)* s = symtab + n;
4270266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    if (strcmp(strtab + s->st_name, name)) continue;
4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // only concern ourselves with global and weak symbol definitions
4300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    switch (ELF_ST_BIND(s->st_info)) {
4310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      case STB_GLOBAL:
4320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      case STB_WEAK:
4330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if (s->st_shndx == SHN_UNDEF) {
434d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov          continue;
435d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov        }
4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
437d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov        TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
4380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                 name, si->name, reinterpret_cast<void*>(s->st_value),
4390266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                 static_cast<size_t>(s->st_size));
440d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov        return s;
441d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov      case STB_LOCAL:
44202aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov        continue;
443d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov      default:
44412bf3bcdeeaa0dcdc7a4f4e4d11bc2fc3bf6bd7aDmitriy Ivanov        __libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'",
44512bf3bcdeeaa0dcdc7a4f4e4d11bc2fc3bf6bd7aDmitriy Ivanov            ELF_ST_BIND(s->st_info), name, si->name);
4461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4470266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
4481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
449aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
450aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov             name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
451aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
452aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
453851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
4541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
456e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovsoinfo::soinfo(const char* name, const struct stat* file_stat, int rtld_flags) {
4570d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  memset(this, 0, sizeof(*this));
4580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
4590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  strlcpy(this->name, name, sizeof(this->name));
4600d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  flags = FLAG_NEW_SOINFO;
4610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  version = SOINFO_VERSION;
4620d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
463851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (file_stat != nullptr) {
4640d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    set_st_dev(file_stat->st_dev);
4650d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    set_st_ino(file_stat->st_ino);
4660d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  }
467e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
468e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  this->rtld_flags = rtld_flags;
4690d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov}
4700d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
471d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstromstatic unsigned elfhash(const char* _name) {
4726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const unsigned char* name = reinterpret_cast<const unsigned char*>(_name);
4736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  unsigned h = 0, g;
4746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
4756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  while (*name) {
4766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    h = (h << 4) + *name++;
4776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    g = h & 0xf0000000;
4786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    h ^= g;
4796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    h ^= g >> 24;
4806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
4816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return h;
4821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
48429bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovstatic ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) {
4856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  unsigned elf_hash = elfhash(name);
4866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Sym)* s = nullptr;
4876ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (somain != nullptr) {
4898f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    DEBUG("%s: looking up %s in executable %s",
4908f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov          si->name, name, somain->name);
4915ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel
4928f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    // 1. Look for it in the main executable
4938f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    s = soinfo_elf_lookup(somain, elf_hash, name);
4948f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    if (s != nullptr) {
4958f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov      *lsi = somain;
4968f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    }
497c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
4988f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    // 2. Look for it in the ld_preloads
4998f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    if (s == nullptr) {
5006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      for (int i = 0; g_ld_preloads[i] != NULL; i++) {
5016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name);
5026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (s != nullptr) {
5038f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov          *lsi = g_ld_preloads[i];
5048f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov          break;
5056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
5066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
5078f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    }
508c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
5098f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    /* Look for symbols in the local scope (the object who is
5108f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     * searching). This happens with C++ templates on x86 for some
5118f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     * reason.
5128f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     *
5138f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     * Notes on weak symbols:
5148f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     * The ELF specs are ambiguous about treatment of weak definitions in
5158f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     * dynamic linking.  Some systems return the first definition found
5168f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     * and some the first non-weak definition.   This is system dependent.
5178f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov     * Here we return the first definition found for simplicity.  */
5186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
5198f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    if (s == nullptr) {
5206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      s = soinfo_elf_lookup(si, elf_hash, name);
5216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (s != nullptr) {
5226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *lsi = si;
5236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
5246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
5256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
5266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
5278f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov  if (s == nullptr) {
5288f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    si->get_children().visit([&](soinfo* child) {
5298f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov      DEBUG("%s: looking up %s in %s", si->name, name, child->name);
5308f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov      s = soinfo_elf_lookup(child, elf_hash, name);
5318f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov      if (s != nullptr) {
5328f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        *lsi = child;
5338f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        return false;
5348f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov      }
5358f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov      return true;
5368f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    });
5378f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov  }
5386ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
5396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (s != nullptr) {
5406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
5416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov               "found in %s, base = %p, load bias = %p",
5426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov               si->name, name, reinterpret_cast<void*>(s->st_value),
5436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov               (*lsi)->name, reinterpret_cast<void*>((*lsi)->base),
5446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov               reinterpret_cast<void*>((*lsi)->load_bias));
5456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
5466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
5478f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov  return s;
5486ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
5496ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
5500cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator.
5510cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
5520cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator {
5530cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
5540cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void* alloc() {
5550cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return allocator_.alloc();
5560cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
5570cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
5580cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(void* ptr) {
5590cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    allocator_.free(ptr);
5600cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
5614bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov
5620cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private:
5630cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static LinkerBlockAllocator allocator_;
5640cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
5650cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
5660cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
5670cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
5680cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
5690cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T>
5700cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator {
5710cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
5720cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static T* alloc() {
5730cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
5740cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
5750cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
5760cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(T* ptr) {
5770cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    SizeBasedAllocator<sizeof(T)>::free(ptr);
5780cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
5790cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
5800cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
58114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask {
58214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public:
58314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct deleter_t {
58414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    void operator()(LoadTask* t) {
58514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      TypeBasedAllocator<LoadTask>::free(t);
58614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
58714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  };
588a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
58914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef UniquePtr<LoadTask, deleter_t> unique_ptr;
590d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom
59114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static deleter_t deleter;
59214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
59314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static LoadTask* create(const char* name, soinfo* needed_by) {
59414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
59514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return new (ptr) LoadTask(name, needed_by);
596aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
597a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
59814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* get_name() const {
59914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return name_;
600a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
60114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
60214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* get_needed_by() const {
60314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return needed_by_;
60414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
60514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private:
60614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTask(const char* name, soinfo* needed_by)
60714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    : name_(name), needed_by_(needed_by) {}
60814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
60914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* name_;
61014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* needed_by_;
61114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
61214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
613aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov};
614aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
61514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T>
61614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
61714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
61814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList;
61914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList;
62014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<LoadTask> LoadTaskList;
62114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
62214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
623aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov// This is used by dlsym(3).  It performs symbol lookup only within the
624aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov// specified soinfo object and its dependencies in breadth first order.
62502aa70589d22fa9b65da43de705d6de2715870c6Dmitriy IvanovElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
6260cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visit_list;
6270cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visited;
6280cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
629aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  visit_list.push_back(si);
630aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  soinfo* current_soinfo;
631aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  while ((current_soinfo = visit_list.pop_front()) != nullptr) {
632042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov    if (visited.contains(current_soinfo)) {
633042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov      continue;
634042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov    }
635042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov
63602aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov    ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name);
637aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
638aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    if (result != nullptr) {
639aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov      *found = current_soinfo;
640aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov      return result;
641aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    }
642042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov    visited.push_back(current_soinfo);
643aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
644aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    current_soinfo->get_children().for_each([&](soinfo* child) {
645aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov      visit_list.push_back(child);
646aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    });
647aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
648aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
649aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  return nullptr;
6501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
652d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the
653d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   start value is null (for RTLD_DEFAULT), the search starts at the
654d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   beginning of the global solist. Otherwise the search starts at the
655d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   specified soinfo (for RTLD_NEXT).
6566ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
65702aa70589d22fa9b65da43de705d6de2715870c6Dmitriy IvanovElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
658cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  unsigned elf_hash = elfhash(name);
6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
660851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (start == nullptr) {
661cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    start = solist;
662cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
6631698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer
664851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  ElfW(Sym)* s = nullptr;
665851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
666e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
667e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov      continue;
668e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    }
669e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
67002aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov    s = soinfo_elf_lookup(si, elf_hash, name);
671851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    if (s != nullptr) {
672cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      *found = si;
673cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      break;
6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
675cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
677851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (s != nullptr) {
678c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
679c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes               name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
680cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
682cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  return s;
6831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
685fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) {
6860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
687851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
688fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (address >= si->base && address - si->base < si->size) {
689fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return si;
690e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
691fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
692851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
693e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
694e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
6950266ae5f884d72da58f33a072e865ba131234a5eElliott HughesElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) {
6960266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - si->base;
697fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
698fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // Search the library's symbol table for any defined symbol which
699fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // contains this address.
700fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  for (size_t i = 0; i < si->nchain; ++i) {
7010266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    ElfW(Sym)* sym = &si->symtab[i];
702fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (sym->st_shndx != SHN_UNDEF &&
703fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng        soaddr >= sym->st_value &&
704fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng        soaddr < sym->st_value + sym->st_size) {
705fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return sym;
706e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
707fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
708e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
709851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
710e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
711e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
712124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library_on_path(const char* name, const char* const paths[]) {
713124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  char buf[512];
714851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (size_t i = 0; paths[i] != nullptr; ++i) {
7151e980b6bc8315d00a07312b25486531247abd98cElliott Hughes    int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
716124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
717ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes      PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name);
718124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes      continue;
7191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
720124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
721124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    if (fd != -1) {
722124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes      return fd;
723124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    }
724124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
725124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  return -1;
7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
728124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library(const char* name) {
729ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ opening %s ]", name);
7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
731124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // If the name contains a slash, we should attempt to open it directly and not search the paths.
732851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (strchr(name, '/') != nullptr) {
7336971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
7346971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    if (fd != -1) {
7356971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes      return fd;
7366971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    }
7376971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now.
7385ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#if defined(__LP64__)
739e43c4a7a665032a29cb5ec15d4adbf81ea199220Dmitriy Ivanov    return -1;
7405ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#endif
741124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
743124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
7441728b2396591853345507a063ed6075dfd251706Elliott Hughes  int fd = open_library_on_path(name, g_ld_library_paths);
745124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  if (fd == -1) {
7461728b2396591853345507a063ed6075dfd251706Elliott Hughes    fd = open_library_on_path(name, kDefaultLdPaths);
747124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
748124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  return fd;
7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
75114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F>
75214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) {
75314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
75414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (d->d_tag == DT_NEEDED) {
75514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      action(si->strtab + d->d_un.d_val);
756d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    }
75714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
75814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
759d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
760e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
76114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  int fd = -1;
76214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ScopedFd file_guard(-1);
763d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
76414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
76514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    fd = extinfo->library_fd;
76614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  } else {
76714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // Open the file.
76814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    fd = open_library(name);
76914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (fd == -1) {
77014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      DL_ERR("library \"%s\" not found", name);
771498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov      return nullptr;
772498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov    }
773b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
77414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    file_guard.reset(fd);
77514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
77623363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner
77714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct stat file_stat;
77814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
77914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno));
78014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
78114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
782d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
78314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Check for symlink and other situations where
78414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // file can have different names.
78514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
78614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (si->get_st_dev() != 0 &&
78714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        si->get_st_ino() != 0 &&
78814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        si->get_st_dev() == file_stat.st_dev &&
78914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        si->get_st_ino() == file_stat.st_ino) {
79014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name);
79114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      return si;
792498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov    }
79314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
794d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
795e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if ((rtld_flags & RTLD_NOLOAD) != 0) {
796a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov    DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
79714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
79814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
799a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
80014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Read the ELF header and load the segments.
80114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ElfReader elf_reader(name, fd);
80214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!elf_reader.Load(extinfo)) {
80314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
80414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
805d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
806e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, rtld_flags);
80714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (si == nullptr) {
80814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
80914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
81014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->base = elf_reader.load_start();
81114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->size = elf_reader.load_size();
81214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->load_bias = elf_reader.load_bias();
81314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phnum = elf_reader.phdr_count();
81414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phdr = elf_reader.loaded_phdr();
81514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
81614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!si->PrelinkImage()) {
81714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo_free(si);
81814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
81914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
820a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
82114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for_each_dt_needed(si, [&] (const char* name) {
82214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, si));
82314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
82414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
82514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
8261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
828489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanovstatic soinfo *find_loaded_library_by_name(const char* name) {
829489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  const char* search_name = SEARCH_NAME(name);
830851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
831489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov    if (!strcmp(search_name, si->name)) {
832489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov      return si;
83312c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel    }
834489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  }
835851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
83612c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel}
83712c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel
838e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
839d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
840489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  soinfo* si = find_loaded_library_by_name(name);
841b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
842b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // Library might still be loaded, the accurate detection
84314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // of this fact is done by load_library.
844851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (si == nullptr) {
845b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov    TRACE("[ '%s' has not been found by name.  Trying harder...]", name);
846e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    si = load_library(load_tasks, name, rtld_flags, extinfo);
847b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  }
848b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
84914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
85014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
85114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
85214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si);
85314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
85414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic bool is_recursive(soinfo* si, soinfo* parent) {
85514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (parent == nullptr) {
85614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return false;
85714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
85814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
85914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (si == parent) {
860b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov    DL_ERR("recursive link to \"%s\"", si->name);
86114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return true;
862d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
863a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
86414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return !parent->get_parents().visit([&](soinfo* grandparent) {
86514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return !is_recursive(si, grandparent);
86614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
867a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov}
868a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
86914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[],
870e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) {
87114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 0: prepare.
87214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTaskList load_tasks;
87314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (size_t i = 0; i < library_names_size; ++i) {
87414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    const char* name = library_names[i];
87514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, nullptr));
87614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
87714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
87814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Libraries added to this list in reverse order so that we can
87914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // start linking from bottom-up - see step 2.
88014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  SoinfoLinkedList found_libs;
88114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  size_t soinfos_size = 0;
88214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
883d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto failure_guard = make_scope_guard([&]() {
88414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // Housekeeping
88514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.for_each([] (LoadTask* t) {
88614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      LoadTask::deleter(t);
88714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    });
88814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
88914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    for (size_t i = 0; i<soinfos_size; ++i) {
89014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      soinfo_unload(soinfos[i]);
89114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
89214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
89314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
89414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
89514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) {
896e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
89714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (si == nullptr) {
89814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      return false;
89914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
90014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
90114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* needed_by = task->get_needed_by();
90214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
90314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (is_recursive(si, needed_by)) {
90414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      return false;
90514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
90614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
907498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov    si->ref_count++;
90814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (needed_by != nullptr) {
90914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      needed_by->add_child(si);
91014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
91114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    found_libs.push_front(si);
91214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
91314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // When ld_preloads is not null first
91414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // ld_preloads_size libs are in fact ld_preloads.
91514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) {
91614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      ld_preloads[soinfos_size] = si;
91714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
91814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
91914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (soinfos_size<library_names_size) {
92014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      soinfos[soinfos_size++] = si;
92114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
92214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
92314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
92414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 2: link libraries.
92514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* si;
92614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  while ((si = found_libs.pop_front()) != nullptr) {
92714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if ((si->flags & FLAG_LINKED) == 0) {
92814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      if (!si->LinkImage(extinfo)) {
92914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        return false;
93014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      }
93114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      si->flags |= FLAG_LINKED;
93214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
933a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
93414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
93514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // All is well - found_libs and load_tasks are empty at this point
93614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // and all libs are successfully linked.
93714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  failure_guard.disable();
93814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return true;
93914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
94014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
941e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
94214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (name == nullptr) {
94314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    somain->ref_count++;
94414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return somain;
94514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
94614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
94714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* si;
94814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
949e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
95014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
95114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
95214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
953d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
954d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
955d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
956b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovstatic void soinfo_unload(soinfo* si) {
957ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  if (si->ref_count == 1) {
958ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    TRACE("unloading '%s'", si->name);
959d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    si->CallDestructors();
960d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
9610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    if (si->has_min_version(0)) {
96214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      soinfo* child = nullptr;
96314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      while ((child = si->get_children().pop_front()) != nullptr) {
96414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        TRACE("%s needs to unload %s", si->name, child->name);
96514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        soinfo_unload(child);
9664bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov      }
967d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    } else {
96814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      for_each_dt_needed(si, [&] (const char* library_name) {
96914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name);
97014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
97114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        if (needed != nullptr) {
97214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov          soinfo_unload(needed);
97314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        } else {
97414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov          // Not found: for example if symlink was deleted between dlopen and dlclose
97514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov          // Since we cannot really handle errors at this point - print and continue.
97614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov          PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name);
977d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov        }
97814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      });
9791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
981d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    notify_gdb_of_unload(si);
982ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    si->ref_count = 0;
983d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov    soinfo_free(si);
984d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  } else {
985ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    si->ref_count--;
986c620059479c47a78d57086d73726c9adc2f337adElliott Hughes    TRACE("not unloading '%s', decrementing ref_count to %zd", si->name, si->ref_count);
987d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
9881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
990a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
991052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Use basic string manipulation calls to avoid snprintf.
992052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
993052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // When debug malloc is enabled, this call returns 0. This in turn causes
994052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf to do nothing, which causes libraries to fail to load.
995052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // See b/17302493 for further details.
996052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Once the above bug is fixed, this code can be modified to use
997052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf again.
998052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
999052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  if (buffer_size < required_len) {
1000052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: buffer len %zu, required len %zu",
1001052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris                 buffer_size, required_len);
1002052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  }
1003052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  char* end = stpcpy(buffer, kDefaultLdPaths[0]);
1004052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  *end = ':';
1005052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  strcpy(end + 1, kDefaultLdPaths[1]);
1006a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes}
1007a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
1008cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
1009cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  if (!get_AT_SECURE()) {
1010cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    parse_LD_LIBRARY_PATH(ld_library_path);
1011cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
1012cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
1013cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
10141a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughessoinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
1015b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) {
1016e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes    DL_ERR("invalid flags to dlopen: %x", flags);
1017851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
1018e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  }
1019851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (extinfo != nullptr && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) {
10203a8646fc5d9f1a9304251a1d1c8ff9e523d81b40Dmitriy Ivanov    DL_ERR("invalid extended flags to android_dlopen_ext: %" PRIx64, extinfo->flags);
1021851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
1022012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  }
1023d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ | PROT_WRITE);
1024b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  soinfo* si = find_library(name, flags, extinfo);
1025851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (si != nullptr) {
1026d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    si->CallConstructors();
1027d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1028d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ);
1029d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
1030d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
10311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1032b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid do_dlclose(soinfo* si) {
1033d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ | PROT_WRITE);
1034b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  soinfo_unload(si);
1035d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ);
10361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10389aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
10399aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  typedef ElfW(Addr) (*ifunc_resolver_t)(void);
10409aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
10419aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ElfW(Addr) ifunc_addr = ifunc_resolver();
10429aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
1043c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
10449aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return ifunc_addr;
1045c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
1046c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
10474eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
104829bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovint soinfo::Relocate(ElfW(Rela)* rela, unsigned count) {
1049c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes  for (size_t idx = 0; idx < count; ++idx, ++rela) {
10500266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    unsigned type = ELFW(R_TYPE)(rela->r_info);
10510266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    unsigned sym = ELFW(R_SYM)(rela->r_info);
105229bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + load_bias);
10530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    ElfW(Addr) sym_addr = 0;
1054851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    const char* sym_name = nullptr;
1055c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
105629bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov    DEBUG("Processing '%s' relocation at index %zd", name, idx);
1057c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    if (type == 0) { // R_*_NONE
1058c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      continue;
1059c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
106014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
106114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    ElfW(Sym)* s = nullptr;
106214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* lsi = nullptr;
106314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1064c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    if (sym != 0) {
106529bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov      sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
106629bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov      s = soinfo_do_lookup(this, sym_name, &lsi);
1067851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov      if (s == nullptr) {
1068c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We only allow an undefined symbol if this is a weak reference...
106929bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov        s = &symtab[sym];
1070c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
107129bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
1072c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes          return -1;
1073c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1074c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1075c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        /* IHI0044C AAELF 4.5.1.1:
1076c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1077c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           Libraries are not searched to resolve weak references.
1078c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           It is not an error for a weak reference to remain unsatisfied.
1079c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1080c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           During linking, the value of an undefined weak reference is:
1081c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - Zero if the relocation type is absolute
1082c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of the place if the relocation is pc-relative
1083c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of nominal base address if the relocation
1084c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes             type is base-relative.
1085c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes         */
1086c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1087c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        switch (type) {
1088e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__)
10896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_JUMP_SLOT:
10906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_GLOB_DAT:
10916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS64:
10926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS32:
10936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS16:
10946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_RELATIVE:
10956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_IRELATIVE:
10966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            /*
10976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * The sym_addr was initialized to be zero above, or the relocation
10986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * code below does not care about value of sym_addr.
10996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * No need to do anything.
11006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             */
11016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
1102e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__)
11036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_X86_64_JUMP_SLOT:
11046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_X86_64_GLOB_DAT:
11056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_X86_64_32:
11066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_X86_64_64:
11076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_X86_64_RELATIVE:
11086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_X86_64_IRELATIVE:
11096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // No need to do anything.
11106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
11116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_X86_64_PC32:
11126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            sym_addr = reloc;
11136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
11144eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
11156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          default:
11166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rela, idx);
11176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            return -1;
1118c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1119c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      } else {
1120c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We got a definition.
11219aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov        sym_addr = lsi->resolve_symbol_address(s);
1122c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      }
1123c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      count_relocation(kRelocSymbol);
1124c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
1125c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1126c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    switch (type) {
1127e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__)
11286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_JUMP_SLOT:
1129e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1130e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
11310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO JMP_SLOT %16llx <- %16llx %s\n",
11320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
11330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend);
1134e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
11356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_GLOB_DAT:
1136e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1137e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
11380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO GLOB_DAT %16llx <- %16llx %s\n",
11390266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
11400266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend);
1141e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
11426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS64:
1143e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1144e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
11450266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
11460266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
11470266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend);
1148e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
11496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS32:
1150e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1151e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
11520266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
11530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
11540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) &&
11550266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) {
11566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend);
1157e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
11586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
11596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)),
11606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT32_MIN),
11616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT32_MAX));
11626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1163e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1164e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
11656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS16:
1166e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1167e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
11680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
11690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
11700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) &&
11710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) {
11726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend);
1173e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
11746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
11756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)),
11766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT16_MIN),
11776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT16_MAX));
11786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1179e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1180e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
11816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL64:
1182e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1183e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
11840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
11850266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name);
11860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend) - rela->r_offset;
1187e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
11886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL32:
1189e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1190e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
11910266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
11920266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name);
11930266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) &&
11940266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) {
11956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset);
1196e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
11976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
11986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)),
11996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT32_MIN),
12006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT32_MAX));
12016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1202e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1203e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
12046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL16:
1205e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1206e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
12070266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
12080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name);
12090266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) &&
12100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) {
12116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset);
1212e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
12136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
12146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)),
12156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT16_MIN),
12166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT16_MAX));
12176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1218e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1219e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1220e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
12216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_RELATIVE:
1222e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1223e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
1224e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        if (sym) {
12256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("odd RELATIVE form...");
12266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1227e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
12280266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n",
122929bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov                   reloc, (base + rela->r_addend));
123029bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (base + rela->r_addend);
1231e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1232e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
12336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_IRELATIVE:
12346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
12356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
12366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend));
12376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + rela->r_addend);
12386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
12399aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
12406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_COPY:
124176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich        /*
124276e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * ET_EXEC is not supported so this should not happen.
124376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
124476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
124576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
124676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * Section 4.7.1.10 "Dynamic relocations"
124776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * R_AARCH64_COPY may only appear in executable objects where e_type is
124876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * set to ET_EXEC.
124976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         */
125029bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov        DL_ERR("%s R_AARCH64_COPY relocations are not supported", name);
125176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich        return -1;
12526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_TPREL64:
12530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
12540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset);
1255e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
12566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_DTPREL32:
12570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
12580266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset);
1259e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1260e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__)
12616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_JUMP_SLOT:
12626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
12636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
12646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast<size_t>(reloc),
12656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr + rela->r_addend), sym_name);
12666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
12676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
12686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_GLOB_DAT:
12696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
12706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
12716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO GLOB_DAT %08zx <- %08zx %s", static_cast<size_t>(reloc),
12726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr + rela->r_addend), sym_name);
12736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
12746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
12756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_RELATIVE:
12766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
12776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
12786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (sym) {
12796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("odd RELATIVE form...");
12806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
12816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
12826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast<size_t>(reloc),
12836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(base));
12846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = base + rela->r_addend;
12856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
12866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_IRELATIVE:
12876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
12886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
12896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend));
12906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + rela->r_addend);
12916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
12926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_32:
12936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
12946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
12956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
12966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
12976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
12986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
12996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_64:
13006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
13016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
13026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
13036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
13046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
13056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
13066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_PC32:
13076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
13086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
13096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
13106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
13116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
13126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend - reloc;
13136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
13144eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
1315e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
13166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
13176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rela, idx);
13186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return -1;
1319c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
1320c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes  }
1321c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes  return 0;
1322c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes}
13239918665a45095ad135576f005c0e5307feb366a1Chris Dearman
13249918665a45095ad135576f005c0e5307feb366a1Chris Dearman#else // REL, not RELA.
132529bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovint soinfo::Relocate(ElfW(Rel)* rel, unsigned count) {
13266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t idx = 0; idx < count; ++idx, ++rel) {
13276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned type = ELFW(R_TYPE)(rel->r_info);
13286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead.
13296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned sym = ELFW(R_SYM)(rel->r_info);
13306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
13316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ElfW(Addr) sym_addr = 0;
13326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    const char* sym_name = nullptr;
13336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
13346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("Processing '%s' relocation at index %zd", name, idx);
13356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (type == 0) { // R_*_NONE
13366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
13376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
13386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
13396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ElfW(Sym)* s = nullptr;
13406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    soinfo* lsi = nullptr;
13416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
13426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (sym != 0) {
13436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
13446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      s = soinfo_do_lookup(this, sym_name, &lsi);
13456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (s == nullptr) {
13466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // We only allow an undefined symbol if this is a weak reference...
13476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        s = &symtab[sym];
13486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
13496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
13506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1351d7daacb46372132ae3f0121647074936c304b572Raghu Gandham        }
135214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
13536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        /* IHI0044C AAELF 4.5.1.1:
13546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
13556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           Libraries are not searched to resolve weak references.
13566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           It is not an error for a weak reference to remain
13576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           unsatisfied.
13586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
13596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           During linking, the value of an undefined weak reference is:
13606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           - Zero if the relocation type is absolute
13616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           - The address of the place if the relocation is pc-relative
13626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           - The address of nominal base address if the relocation
13636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             type is base-relative.
13646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        */
13656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
13666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        switch (type) {
13674eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
13686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_ARM_JUMP_SLOT:
13696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_ARM_GLOB_DAT:
13706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_ARM_ABS32:
13716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_ARM_RELATIVE:    /* Don't care. */
13726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // sym_addr was initialized to be zero above or relocation
13736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // code below does not care about value of sym_addr.
13746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // No need to do anything.
13756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
13764eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
13776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_JMP_SLOT:
13786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_GLOB_DAT:
13796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_32:
13806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_RELATIVE:    /* Don't care. */
13816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_IRELATIVE:
13826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // sym_addr was initialized to be zero above or relocation
13836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // code below does not care about value of sym_addr.
13846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // No need to do anything.
13856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
13866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_PC32:
13876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            sym_addr = reloc;
13886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
13894eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
1390e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan
13914eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
13926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_ARM_COPY:
13936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // Fall through. Can't really copy if weak symbol is not found at run-time.
13944eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
13956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          default:
13966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
13976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            return -1;
13981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
13996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      } else {
14006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // We got a definition.
14016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        sym_addr = lsi->resolve_symbol_address(s);
14026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
14036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      count_relocation(kRelocSymbol);
14046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
14051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    switch (type) {
14074eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
14086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_JUMP_SLOT:
14096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
14106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
14126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
14136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_GLOB_DAT:
14156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
14166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
14186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
14196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_ABS32:
14216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
14226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
14246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
14256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_REL32:
14276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
14286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
14306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, sym_addr, rel->r_offset, sym_name);
14316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
14326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_COPY:
14346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        /*
14356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * ET_EXEC is not supported so this should not happen.
14366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
14376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
14386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
14396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * Section 4.7.1.10 "Dynamic relocations"
14406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * R_ARM_COPY may only appear in executable objects where e_type is
14416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * set to ET_EXEC.
14426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         */
14436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("%s R_ARM_COPY relocations are not supported", name);
14446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return -1;
14454eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
14466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_JMP_SLOT:
14476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
14486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
14506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
14516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_GLOB_DAT:
14536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
14546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
14566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
14576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_32:
14596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
14606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
14626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
14636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_PC32:
14656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
14666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
14686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
14696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
14706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14714eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__mips__)
14726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_MIPS_REL32:
14739918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if defined(__LP64__)
14746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // MIPS Elf64_Rel entries contain compound relocations
14756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case
14766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 ||
14776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) {
14786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)",
14796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 type, (unsigned)ELF64_R_TYPE2(rel->r_info),
14806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx);
14816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
14826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
14839918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif
14846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
14856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
14866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc),
14876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*");
14886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (s) {
14896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
14906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        } else {
14916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
14926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
14936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14944eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
14954eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes
14964eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
14976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_RELATIVE:
14984eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
14996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_RELATIVE:
15004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
15016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
15026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
15036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (sym) {
15046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("odd RELATIVE form...");
15056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
15066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
15076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p",
15086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
15096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
15106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
15119aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#if defined(__i386__)
15126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_IRELATIVE:
15136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
15146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
15156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
15166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + *reinterpret_cast<ElfW(Addr)*>(reloc));
15176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
15189aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif
15191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
15216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
15226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return -1;
15231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
15256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return 0;
15261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1527c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
15281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15294eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
153029bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovstatic bool mips_relocate_got(soinfo* si) {
15316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Addr)** got = si->plt_got;
15326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (got == nullptr) {
15336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return true;
15346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
15356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  unsigned local_gotno = si->mips_local_gotno;
15366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  unsigned gotsym = si->mips_gotsym;
15376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  unsigned symtabno = si->mips_symtabno;
15386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Sym)* symtab = si->symtab;
15396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
15406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // got[0] is the address of the lazy resolver function.
15416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // got[1] may be used for a GNU extension.
15426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Set it to a recognizable address in case someone calls it (should be _rtld_bind_start).
15436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // FIXME: maybe this should be in a separate routine?
15446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if ((si->flags & FLAG_LINKER) == 0) {
15456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    size_t g = 0;
15466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadbeef);
15476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (reinterpret_cast<intptr_t>(got[g]) < 0) {
15486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadfeed);
154987c358524e479235aa6241736d2ce325f89daafcBrian Carlstrom    }
15506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // Relocate the local GOT entries.
15516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    for (; g < local_gotno; g++) {
15526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      got[g] = reinterpret_cast<ElfW(Addr)*>(reinterpret_cast<uintptr_t>(got[g]) + si->load_bias);
1553d7daacb46372132ae3f0121647074936c304b572Raghu Gandham    }
15546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1555d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
15566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Now for the global GOT entries...
15576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Sym)* sym = symtab + gotsym;
15586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  got = si->plt_got + local_gotno;
15596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t g = gotsym; g < symtabno; g++, sym++, got++) {
15606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // This is an undefined reference... try to locate it.
15616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    const char* sym_name = si->strtab + sym->st_name;
15626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    soinfo* lsi = nullptr;
15636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi);
15646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (s == nullptr) {
15656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      // We only allow an undefined symbol if this is a weak reference.
15666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      s = &symtab[g];
15676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
15686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("cannot locate \"%s\"...", sym_name);
15696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
15706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
15716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      *got = 0;
15726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    } else {
15736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      // FIXME: is this sufficient?
15746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      // For reference see NetBSD link loader
15756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      // http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/arch/mips/mips_reloc.c?rev=1.53&content-type=text/x-cvsweb-markup
15766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      *got = reinterpret_cast<ElfW(Addr)*>(lsi->resolve_symbol_address(s));
1577d7daacb46372132ae3f0121647074936c304b572Raghu Gandham    }
15786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
15796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
1580d7daacb46372132ae3f0121647074936c304b572Raghu Gandham}
1581d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif
1582d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
1583812fd4263a005b88f3b4222baa910114f938d594Kito Chengvoid soinfo::CallArray(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) {
1584851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (functions == nullptr) {
1585d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
1586d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
15878215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1588c620059479c47a78d57086d73726c9adc2f337adElliott Hughes  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, name);
15898215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1590ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int begin = reverse ? (count - 1) : 0;
1591ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int end = reverse ? -1 : count;
1592ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int step = reverse ? -1 : 1;
15938215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1594ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  for (int i = begin; i != end; i += step) {
1595ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
1596ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    CallFunction("function", functions[i]);
1597d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1598d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1599ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ Done calling %s for '%s' ]", array_name, name);
16001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1602812fd4263a005b88f3b4222baa910114f938d594Kito Chengvoid soinfo::CallFunction(const char* function_name __unused, linker_function_t function) {
1603851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
1604d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
1605d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1606d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1607ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, name);
1608d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  function();
1609ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, name);
1610db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes
1611db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes  // The function may have called dlopen(3) or dlclose(3), so we need to ensure our data structures
1612db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes  // are still writable. This happens with our debug malloc (see http://b/7941716).
1613d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ | PROT_WRITE);
16149181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov}
16159181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
1616d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallPreInitConstructors() {
16178147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
16188147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // but ignored in a shared library.
1619d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  CallArray("DT_PREINIT_ARRAY", preinit_array, preinit_array_count, false);
1620d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
1621e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
1622d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallConstructors() {
1623d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  if (constructors_called) {
1624d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
1625d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1626e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
1627d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // We set constructors_called before actually calling the constructors, otherwise it doesn't
1628d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // protect against recursive constructor calls. One simple example of constructor recursion
1629d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
1630d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 1. The program depends on libc, so libc's constructor is called here.
1631d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
1632d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 3. dlopen() calls the constructors on the newly created
1633d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    soinfo for libc_malloc_debug_leak.so.
1634d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 4. The debug .so depends on libc, so CallConstructors is
1635d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    called again with the libc soinfo. If it doesn't trigger the early-
1636d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    out above, the libc constructor will be called again (recursively!).
1637d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  constructors_called = true;
1638d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1639851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) {
16408147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes    // The GNU dynamic linker silently ignores these, but we warn the developer.
1641c620059479c47a78d57086d73726c9adc2f337adElliott Hughes    PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
16428147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes          name, preinit_array_count);
1643d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1645d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  get_children().for_each([] (soinfo* si) {
1646d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    si->CallConstructors();
1647d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
16481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16498147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  TRACE("\"%s\": calling constructors", name);
16508147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
16518147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_INIT should be called before DT_INIT_ARRAY if both are present.
1652d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  CallFunction("DT_INIT", init_func);
1653d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
1654e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov}
16558215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1656d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallDestructors() {
165714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!constructors_called) {
165814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return;
165914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
16608147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  TRACE("\"%s\": calling destructors", name);
16618147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
16628147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI_ARRAY must be parsed in reverse order.
1663d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  CallArray("DT_FINI_ARRAY", fini_array, fini_array_count, true);
16648147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
16658147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI should be called after DT_FINI_ARRAY if both are present.
1666d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  CallFunction("DT_FINI", fini_func);
1667b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
1668b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // This is needed on second call to dlopen
1669b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // after library has been unloaded with RTLD_NODELETE
1670b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  constructors_called = false;
16711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1673d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) {
16740d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
1675b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov    child->parents.push_back(this);
1676b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov    this->children.push_back(child);
1677d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1678d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1679d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1680d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() {
16810d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (!has_min_version(0)) {
1682d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    return;
1683d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1684d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1685d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 1. Untie connected soinfos from 'this'.
1686d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  children.for_each([&] (soinfo* child) {
1687d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    child->parents.remove_if([&] (const soinfo* parent) {
1688d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return parent == this;
1689d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
1690d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
1691d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1692d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  parents.for_each([&] (soinfo* parent) {
16934bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov    parent->children.remove_if([&] (const soinfo* child) {
1694d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return child == this;
1695d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
1696d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
1697d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1698d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 2. Once everything untied - clear local lists.
1699d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  parents.clear();
1700d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  children.clear();
1701d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1702d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1703d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::set_st_dev(dev_t dev) {
17040d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
17050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    st_dev = dev;
1706d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1707d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1708d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1709d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::set_st_ino(ino_t ino) {
17100d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
17110d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    st_ino = ino;
1712d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1713d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1714d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1715d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovdev_t soinfo::get_st_dev() {
17160d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
17170d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    return st_dev;
1718d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1719d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
17200d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
1721d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov};
1722d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1723d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovino_t soinfo::get_st_ino() {
17240d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
17250d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    return st_ino;
1726d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1727d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
17280d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
1729d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1730d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1731e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovint soinfo::get_rtld_flags() {
1732e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if (has_min_version(1)) {
1733e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    return rtld_flags;
1734e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  }
1735e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
1736e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  return 0;
1737e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
1738e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
173914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if
1740d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set.
1741d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list;
1742d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1743d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() {
17440d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
17450d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov    return this->children;
1746d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1747d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
17480d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return g_empty_list;
1749d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1750d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
175114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() {
175214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if ((this->flags & FLAG_NEW_SOINFO) == 0) {
175314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return g_empty_list;
175414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
175514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
175614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return this->parents;
175714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
175814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
17599aea164457c269c475592da36b4655d45f55c7bcDmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) {
17609aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
17619aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov    return call_ifunc_resolver(s->st_value + load_bias);
17629aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  }
17639aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
17649aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return static_cast<ElfW(Addr)>(s->st_value + load_bias);
17659aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov}
17669aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
17671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with
17681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   /dev/null. */
17695419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic int nullify_closed_stdio() {
17706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int dev_null, i, status;
17716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int return_value = 0;
17721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
17746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dev_null < 0) {
17756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("cannot open /dev/null: %s", strerror(errno));
17766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return -1;
17776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
17786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null);
17796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
17806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* If any of the stdio file descriptors is valid and not associated
17816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov     with /dev/null, dup /dev/null to it.  */
17826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (i = 0; i < 3; i++) {
17836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* If it is /dev/null already, we are done. */
17846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (i == dev_null) {
17856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
17861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE("[ Nullifying stdio file descriptor %d]", i);
17896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
17901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* If file is opened, we are good. */
17926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status != -1) {
17936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
17946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
17951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* The only error we allow is that the file descriptor does not
17976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       exist, in which case we dup /dev/null to it. */
17986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (errno != EBADF) {
17996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("fcntl failed: %s", strerror(errno));
18006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
18016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
18026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
18031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* Try dupping /dev/null to this stdio file descriptor and
18056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       repeat if there is a signal.  Note that any errors in closing
18066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       the stdio descriptor are lost.  */
18076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
18086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status < 0) {
18096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("dup2 failed: %s", strerror(errno));
18106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
18116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
18121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
18141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* If /dev/null is not one of the stdio file descriptors, close it. */
18166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dev_null > 2) {
18176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null);
18186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(close(dev_null));
18196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status == -1) {
18206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("close failed: %s", strerror(errno));
18216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
18241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return return_value;
18261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
18271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
182814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovbool soinfo::PrelinkImage() {
18296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic);
1830498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov
18316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can't log anything until the linker is relocated */
18326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  bool relocating_linker = (flags & FLAG_LINKER) != 0;
18336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!relocating_linker) {
18346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    INFO("[ linking %s ]", name);
18356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags);
18366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
18376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
18386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Extract dynamic section */
18396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Word) dynamic_flags = phdr->p_flags;
18406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dynamic == nullptr) {
1841b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    if (!relocating_linker) {
18426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("missing PT_DYNAMIC in \"%s\"", name);
1843b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    }
18446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
18456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
18466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (!relocating_linker) {
18476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DEBUG("dynamic = %p", dynamic);
184863f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner    }
18496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
185063f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
18514eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
18526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
18536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                  &ARM_exidx, &ARM_exidx_count);
185463f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif
185563f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
18566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract useful information from dynamic section.
18576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  uint32_t needed_count = 0;
18586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
18596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
18606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
18616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    switch (d->d_tag) {
18624a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SONAME:
18634a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // TODO: glibc dynamic linker uses this name for
18644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // initial library lookup; consider doing the same here.
18654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
18666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_HASH:
18676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
18686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
18696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
18706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4);
18716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
18726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_STRTAB:
18736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
18746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
18756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMTAB:
18766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
18776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
18784a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SYMENT:
18794a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Sym))) {
1880f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_SYMENT: %zd", static_cast<size_t>(d->d_un.d_val));
18814a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
18824a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
18834a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
18844eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if !defined(__LP64__)
18856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTREL:
18866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val != DT_REL) {
18876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("unsupported DT_RELA in \"%s\"", name);
18886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
18896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
18906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
1891c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
18926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_JMPREL:
18934eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
18946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        plt_rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
1895c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
18966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        plt_rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
1897c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
18986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
18996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTRELSZ:
19004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
19016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
1902c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
19036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
1904c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
19056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTGOT:
19074a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__)
19086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Used by mips and mips64.
19096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        plt_got = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
1910c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
19114a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // Ignore for other platforms... (because RTLD_LAZY is not supported)
19124a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
19136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_DEBUG:
19146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_DEBUG entry to the address of _r_debug for GDB
19156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // if the dynamic table is writable
19169918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64
19179918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree.
191814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as
19199918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable.
19209918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__))
19216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if ((dynamic_flags & PF_W) != 0) {
19226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
19236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
19246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19259918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif
19264eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
19276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
19286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
19296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELASZ:
19316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
19326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19334a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELAENT:
19344a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rela))) {
1935f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
19364a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
19374a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
19384a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
19394a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELACOUNT:
19404a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // ignored (see DT_RELCOUNT comments for details)
19414a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
19426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
19436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unsupported DT_REL in \"%s\"", name);
19446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
19456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
19466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unsupported DT_RELSZ in \"%s\"", name);
19476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
1948c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
19496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
19506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
19516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
19536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
19546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19554a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELENT:
19564a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rel))) {
1957f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
19584a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
19594a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
19604a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
19614a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELCOUNT:
19624a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // "Indicates that all RELATIVE relocations have been concatenated together,
19634a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // and specifies the RELATIVE relocation count."
19644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        //
19654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // TODO: Spec also mentions that this can be used to optimize relocation process;
19664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // Not currently used by bionic linker - ignored.
19674a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
19686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
19696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unsupported DT_RELA in \"%s\"", name);
19706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
1971c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
19726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT:
19736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        init_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
19746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DEBUG("%s constructors (DT_INIT) found at %p", name, init_func);
19756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI:
19776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        fini_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
19786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func);
19796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAY:
19816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        init_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
19826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array);
19836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAYSZ:
19856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
19866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAY:
19886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        fini_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
19896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array);
19906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAYSZ:
19926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
19936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAY:
19956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        preinit_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
19966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array);
19976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
19986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAYSZ:
19996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
20006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_TEXTREL:
2002e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__)
20036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name);
20046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2005e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else
20066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        has_text_relocations = true;
20076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2008e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
20096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMBOLIC:
20108f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        // ignored
20116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_NEEDED:
20136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        ++needed_count;
20146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FLAGS:
20166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val & DF_TEXTREL) {
2017e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__)
20186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name);
20196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
2020e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else
20216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          has_text_relocations = true;
2022e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
20236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
20246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20254eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
20266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_STRSZ:
20276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_MAP:
20296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
20306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        {
20316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
20326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *dp = &_r_debug;
20336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
20346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_VERSION:
20366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_FLAGS:
20376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_BASE_ADDRESS:
20386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_UNREFEXTNO:
20396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2040d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
20416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_SYMTABNO:
20426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        mips_symtabno = d->d_un.d_val;
20436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2044d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
20456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_LOCAL_GOTNO:
20466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        mips_local_gotno = d->d_un.d_val;
20476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2048d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
20496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_GOTSYM:
20506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        mips_gotsym = d->d_un.d_val;
20516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20524eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
2053d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
20546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
20558f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        if (!relocating_linker) {
20568f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov          DL_WARN("%s: unused DT entry: type %p arg %p", name,
20578f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov              reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
20588f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        }
20596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
20616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
20646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        reinterpret_cast<void*>(base), strtab, symtab);
20651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Sanity checks.
20676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (relocating_linker && needed_count != 0) {
20686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
20696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
20706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (nbucket == 0) {
20726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name);
20736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
20746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (strtab == 0) {
20766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("empty/missing DT_STRTAB in \"%s\"", name);
20776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
20786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (symtab == 0) {
20806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name);
20816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
20826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
208414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
20851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
208614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovbool soinfo::LinkImage(const android_dlextinfo* extinfo) {
20871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2088e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__)
20896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (has_text_relocations) {
20906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // Make segments writable to allow text relocations to work properly. We will later call
20916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
20926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_WARN("%s has text relocations. This is wasting memory and prevents "
20936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            "security hardening. Please fix.", name);
20946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
20956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("can't unprotect loadable segments for \"%s\": %s",
20966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
20976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
20985135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich    }
20996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2100e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
21015135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich
21024eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
21036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (rela != nullptr) {
21046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s ]", name);
21056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (Relocate(rela, rela_count)) {
21066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2107c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
21086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (plt_rela != nullptr) {
21106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s plt ]", name);
21116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (Relocate(plt_rela, plt_rela_count)) {
21126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
21131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
21146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21159aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else
21166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (rel != nullptr) {
21176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s ]", name);
21186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (Relocate(rel, rel_count)) {
21196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
21201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
21216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (plt_rel != nullptr) {
21236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s plt ]", name);
21246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (Relocate(plt_rel, plt_rel_count)) {
21256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2126c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith    }
21276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21289aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif
2129c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
21304eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
21316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!mips_relocate_got(this)) {
21326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
21336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2134d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif
2135d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
21366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  DEBUG("[ finished linking %s ]", name);
21371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2138e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__)
21396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (has_text_relocations) {
21406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // All relocations are done, we can protect our segments back to read-only.
21416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
21426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("can't protect segments for \"%s\": %s",
21436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
21446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
21451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
21466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2147e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
21481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can also turn on GNU RELRO protection */
21506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
21516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
21526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           name, strerror(errno));
21536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
21546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21559ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich
21566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Handle serializing/sharing the RELRO segment */
21576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
21586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
21596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                       extinfo->relro_fd) < 0) {
21606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
21616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
21626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2163183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)    }
21646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
21656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
21666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                 extinfo->relro_fd) < 0) {
21676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
21686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
21696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
21706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
21716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2172183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)
21736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  notify_gdb_of_load(this);
21746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
21751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
21761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2177468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
2178c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list.
2179c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers.
2180c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc.
2181c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */
2182812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) {
21834eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR)
21840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
2185851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (ehdr_vdso == nullptr) {
21860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    return;
21870266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
2188c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
2189e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0);
2190ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
21910266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
21920266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phnum = ehdr_vdso->e_phnum;
21930266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
21940266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
21950266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
2196ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
219714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->PrelinkImage();
219829bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov  si->LinkImage(nullptr);
2199c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif
2200c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
2201c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
2202c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/*
2203d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below.
2204d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
22050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__)
22060d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64"
22070d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else
22080d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker"
22090d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif
2210e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0);
2211d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2212d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list.
2213d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text"
2214d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to
2215d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
2216d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't
2217d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list.
2218d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
2219d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
2220d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  linker_soinfo_for_gdb.base = linker_base;
2221d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2222d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  /*
2223d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * Set the dynamic field in the link map otherwise gdb will complain with
2224d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * the following:
2225d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   warning: .dynamic section for "/system/bin/linker" is not at the
2226d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   expected address (wrong library or version mismatch?)
2227d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   */
2228d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
2229d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
2230d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
223114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov                                 &linker_soinfo_for_gdb.dynamic);
2232d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  insert_soinfo_into_debug_map(&linker_soinfo_for_gdb);
2233d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2234d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2235d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/*
2236468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and
2237468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs
2238468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point.
2239468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
22400266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
22411a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING
22426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  struct timeval t0, t1;
22436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t0, 0);
22441a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif
22451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Initialize environment functions, and get to the ELF aux vectors table.
22476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  linker_env_init(args);
2248be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
22496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // If this is a setuid/setgid program, close the security hole described in
22506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
22516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (get_AT_SECURE()) {
22526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    nullify_closed_stdio();
22536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
22548d3e91d4f842911366155845afb3cfbdad0b4cadNick Kralevich
22556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  debuggerd_init();
22561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Get a few environment variables.
22586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* LD_DEBUG = linker_env_get("LD_DEBUG");
22596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (LD_DEBUG != nullptr) {
22606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    g_ld_debug_verbosity = atoi(LD_DEBUG);
22616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2262be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
22636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Normally, these are cleaned by linker_env_init, but the test
22646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // doesn't cost us anything.
22656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpath_env = nullptr;
22666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpreload_env = nullptr;
22676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!get_AT_SECURE()) {
22686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ldpath_env = linker_env_get("LD_LIBRARY_PATH");
22696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ldpreload_env = linker_env_get("LD_PRELOAD");
22706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
22711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  INFO("[ android linker & debugger ]");
22731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2274e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  soinfo* si = soinfo_alloc(args.argv[0], nullptr, RTLD_GLOBAL);
22756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
22766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
22776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
22781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* bootstrap the link map, the main exe always needs to be first */
22806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->flags |= FLAG_EXE;
22816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(si->link_map_head);
22821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = 0;
22846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_name = args.argv[0];
22856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_prev = nullptr;
22866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_next = nullptr;
22871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_map = map;
22896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
22901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  init_linker_info_for_gdb(linker_base);
22921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract information passed from the kernel.
22946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
22956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phnum = args.getauxval(AT_PHNUM);
22966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->entry = args.getauxval(AT_ENTRY);
22971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Compute the value of si->base. We can't rely on the fact that
22996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * the first entry is the PHDR because this will not be true
23006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * for certain executables (e.g. some in the NDK unit test suite)
23016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   */
23026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->base = 0;
23036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
23046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->load_bias = 0;
23056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t i = 0; i < si->phnum; ++i) {
23066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (si->phdr[i].p_type == PT_PHDR) {
23076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
23086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
23096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
23108180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner    }
23116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
23126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->dynamic = nullptr;
23136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->ref_count = 1;
23141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
23156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
23166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (elf_hdr->e_type != ET_DYN) {
23176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n");
23186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
23196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
23202aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich
23216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
23226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_LIBRARY_PATH(ldpath_env);
23236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_PRELOAD(ldpreload_env);
23244fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
23256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  somain = si;
23265ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel
23276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->PrelinkImage();
232814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Load ld_preloads and dependencies.
23306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  StringLinkedList needed_library_name_list;
23316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t needed_libraries_count = 0;
23326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t ld_preloads_count = 0;
23336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  while (g_ld_preload_names[ld_preloads_count] != nullptr) {
23346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]);
23356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
23366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
233714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for_each_dt_needed(si, [&](const char* name) {
23396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    needed_library_name_list.push_back(name);
23406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
23416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  });
234214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* needed_library_names[needed_libraries_count];
23446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  soinfo* needed_library_si[needed_libraries_count];
234514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  memset(needed_library_names, 0, sizeof(needed_library_names));
23476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
234814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
2349e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
23506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer());
23516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
23526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
235314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t i = 0; i<needed_libraries_count; ++i) {
23556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    si->add_child(needed_library_si[i]);
23566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
235714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!si->LinkImage(nullptr)) {
23596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
23606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
23616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
23621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
23636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  add_vdso(args);
2364c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
23656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->CallPreInitConstructors();
23669181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
23676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* After the PrelinkImage, the si->load_bias is initialized.
23686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
23696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * We need to update this value for so exe here. So Unwind_Backtrace
23706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * for some arch like x86 could work correctly within so exe.
23716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   */
23726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = si->load_bias;
23736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->CallConstructors();
2374e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
23751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
23766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t1, nullptr);
23776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
23786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
23796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
23801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
23811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
23826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0],
23836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocAbsolute],
23846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocRelative],
23856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocCopy],
23866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocSymbol]);
23871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
23881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
23896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  {
23906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned n;
23916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned i;
23926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned count = 0;
23936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    for (n = 0; n < 4096; n++) {
23946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (bitmask[n]) {
23956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        unsigned x = bitmask[n];
2396e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__)
23976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 32; i++) {
2398e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else
23996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 8; i++) {
2400e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif
24016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          if (x & 1) {
24026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            count++;
24036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          }
24046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          x >>= 1;
24051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
24066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
24071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
24086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4);
24096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
24111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
24136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  fflush(stdout);
24141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
24151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  TRACE("[ Ready to execute '%s' @ %p ]", si->name, reinterpret_cast<void*>(si->entry));
24176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return si->entry;
24181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2419468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
2420bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only
2421bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library
2422bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself.
2423bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *
2424bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input:
2425bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    elf    -> address of ELF header, assumed to be at the start of the file.
2426bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return:
2427bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    load bias, i.e. add the value of any p_vaddr in the file to get
2428bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    the corresponding address in memory.
2429bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */
24300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
24310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) offset = elf->e_phoff;
2432faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  const ElfW(Phdr)* phdr_table = reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
24330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
2434fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
24350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
2436fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (phdr->p_type == PT_LOAD) {
24370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
2438bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner    }
2439fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
2440fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  return 0;
2441bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner}
2442bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner
2443efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start();
2444efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
2445468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
2446468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This
2447468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and
2448468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation().
2449468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich *
2450468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own
2451468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern
2452468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault.
2453468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
24540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) {
245542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  KernelArgumentBlock args(raw_args);
245642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
24570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
2458efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
24590266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
2460faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
246142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
2462e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  soinfo linker_so("[dynamic linker]", nullptr, 0);
246342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
2464efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // If the linker is not acting as PT_INTERP entry_point is equal to
2465efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // _start. Which means that the linker is running as an executable and
2466efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // already linked by PT_INTERP.
2467efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  //
2468efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // This happens when user tries to run 'adb shell /system/bin/linker'
2469efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // see also https://code.google.com/p/android/issues/detail?id=63174
2470efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
2471efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
2472efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  }
2473efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
247442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.base = linker_addr;
247542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
247642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
2477851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  linker_so.dynamic = nullptr;
247842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phdr = phdr;
247942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phnum = elf_hdr->e_phnum;
248042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.flags |= FLAG_LINKER;
248142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
248214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) {
248342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // It would be nice to print an error message, but if the linker
248442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // can't link itself, there's no guarantee that we'll be able to
2485b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // call write() (because it involves a GOT reference). We may as
2486b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // well try though...
2487b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    const char* msg = "CANNOT LINK EXECUTABLE: ";
2488b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, msg, strlen(msg));
2489b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
2490b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, "\n", 1);
2491b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    _exit(EXIT_FAILURE);
249242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
2493468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
249414241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov  __libc_init_tls(args);
249514241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov
2496efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // Initialize the linker's own global variables
24974151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov  linker_so.CallConstructors();
24984151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov
24990d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // Initialize static variables. Note that in order to
25000d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // get correct libdl_info we need to call constructors
25010d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // before get_libdl_info().
25020d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  solist = get_libdl_info();
25030d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  sonext = get_libdl_info();
25040d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
250542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // We have successfully fixed our own relocations. It's safe to run
250642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // the main part of the linker now.
25071728b2396591853345507a063ed6075dfd251706Elliott Hughes  args.abort_message_ptr = &g_abort_message;
25080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
25095419b9474753d25dff947c7740532f86d130c0beElliott Hughes
2510d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ);
2511d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
251242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // Return the address that the calling assembly stub should jump to.
251342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  return start_address;
2514468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich}
2515