linker.cpp revision 1b694693b47785c5350916eafc9200cf9aa4a920
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>
38ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#include <sys/param.h>
39bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#include <sys/personality.h>
404688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h>
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
420d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new>
430d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
444688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers.
45eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h"
46eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h"
47eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h"
4804dc91ae763adc403a14c88b4c46f77b3d2d71a3Dmitriy Ivanov#include "private/ScopedFd.h"
4914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/ScopeGuard.h"
5014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/UniquePtr.h"
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h"
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h"
54be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner#include "linker_environ.h"
5523363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h"
56cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#include "linker_relocs.h"
57d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include "linker_allocator.h"
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here.
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past.
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo:
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   and NOEXEC
724688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes */
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
74489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#if defined(__LP64__)
75489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#define SEARCH_NAME(x) x
76489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#else
77489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// Nvidia drivers are relying on the bug:
78489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// http://code.google.com/p/android/issues/detail?id=6670
79489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// so we continue to use base-name lookup for lp32
80489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanovstatic const char* get_base_name(const char* name) {
81489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  const char* bname = strrchr(name, '/');
82489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  return bname ? bname + 1 : name;
83489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov}
84489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#define SEARCH_NAME(x) get_base_name(x)
85489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#endif
86489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov
870266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
891728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic LinkerAllocator<soinfo> g_soinfo_allocator;
90d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic LinkerAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
91ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
92d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist;
93d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext;
946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
961728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = {
974eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__)
98011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/vendor/lib64",
99011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/system/lib64",
100011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else
101124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/vendor/lib",
102124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/system/lib",
103011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif
104851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  nullptr
105124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes};
106124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
107a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPATH_BUFSIZE (LDPATH_MAX*64)
108a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPATH_MAX 8
109a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
110a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPRELOAD_BUFSIZE (LDPRELOAD_MAX*64)
111a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPRELOAD_MAX 8
112a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
1131728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic char g_ld_library_paths_buffer[LDPATH_BUFSIZE];
1141728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* g_ld_library_paths[LDPATH_MAX + 1];
115bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1161728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic char g_ld_preloads_buffer[LDPRELOAD_BUFSIZE];
1171728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* g_ld_preload_names[LDPRELOAD_MAX + 1];
1184fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
1191728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic soinfo* g_ld_preloads[LDPRELOAD_MAX + 1];
1204fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
1211728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity;
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
123851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
1240d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes
125bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesenum RelocationKind {
1266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocAbsolute = 0,
1276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocRelative,
1286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocCopy,
1296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocSymbol,
1306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  kRelocMax
131bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes};
132be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
134bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t {
1356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int count[kRelocMax];
136bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes};
137bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
138bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats;
139bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
140bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void count_relocation(RelocationKind kind) {
1416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ++linker_stats.count[kind];
142bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
143bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else
144bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void count_relocation(RelocationKind) {
145bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
149bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic unsigned bitmask[4096];
150e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__)
151e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#define MARK(offset) \
152e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland    do { \
1536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if ((((offset) >> 12) >> 5) < 4096) \
1546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \
155faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes    } while (0)
156e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else
157bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#define MARK(offset) \
158bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes    do { \
1596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
160faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes    } while (0)
161e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif
162bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else
163bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#define MARK(x) do {} while (0)
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1664688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// You shouldn't try to call memory-allocating functions in the dynamic linker.
1674688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Guard against the most obvious ones.
1688f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#define DISALLOW_ALLOCATION(return_type, name, ...) \
1698f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes    return_type name __VA_ARGS__ \
1708f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes    { \
1716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      __libc_fatal("ERROR: " #name " called from the dynamic linker!\n"); \
1724688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes    }
173812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, malloc, (size_t u __unused));
174812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void, free, (void* u __unused));
175812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, realloc, (void* u1 __unused, size_t u2 __unused));
176812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, calloc, (size_t u1 __unused, size_t u2 __unused));
1772e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1782e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1792e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
180650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() {
1815419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return &__linker_dl_err_buf[0];
1822e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1832e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
184650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() {
185650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes  return sizeof(__linker_dl_err_buf);
186650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes}
187650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes
1886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified
1896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity.
1905419b9474753d25dff947c7740532f86d130c0beElliott Hughesextern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1921728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
193851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanovstatic r_debug _r_debug = {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
1943a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0;
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1963a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) {
1976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Copy the necessary fields into the debug structure.
1986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = info->load_bias;
200c9d16583972a4d329b91960148172d41ed04ab37Dmitriy Ivanov  map->l_name = info->name;
2016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_ld = info->dynamic;
2026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
2036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Stick the new library at the end of the list.
2046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // gdb tends to care more about libc than it does
2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // about leaf libraries, and ordering it this way
2066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // reduces the back-and-forth over the wire.
2076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail) {
2086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail->l_next = map;
2096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = r_debug_tail;
2106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
2116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
2126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    _r_debug.r_map = map;
2136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = 0;
2146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
2156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
2171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
219bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) {
2206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
2215e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail == map) {
2236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail = map->l_prev;
2246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2255e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_prev) {
2276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev->l_next = map->l_next;
2286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_next) {
2306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next->l_prev = map->l_prev;
2316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2325e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2335e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
234bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) {
235ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
2366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
2376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_ADD;
2436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  insert_soinfo_into_debug_map(info);
2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2495e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2505e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
251bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) {
252ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
2536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
2546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2565e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2585e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_DELETE;
2606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2615e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  remove_soinfo_from_debug_map(info);
2635e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26818a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() {
2693a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_ADD;
2703a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2713a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_CONSISTENT;
2723a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
275d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
276d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  return g_soinfo_links_allocator.alloc();
277d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
278d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
279d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
280d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_links_allocator.free(entry);
281d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
282d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
283d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void protect_data(int protection) {
284d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_allocator.protect_all(protection);
285d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_links_allocator.protect_all(protection);
286d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
287d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
288d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, uint32_t rtld_flags) {
289ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  if (strlen(name) >= SOINFO_NAME_LEN) {
290ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn    DL_ERR("library name \"%s\" too long", name);
291851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
292ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  }
293ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
29407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
295d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
296ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext->next = si;
297ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext = si;
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
299ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("name %s: allocated soinfo @ %p", name, si);
300ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  return si;
3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
303faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) {
3046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
3056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
3066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3074688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si->base != 0 && si->size != 0) {
3096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    munmap(reinterpret_cast<void*>(si->base), si->size);
3106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
311d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  soinfo *prev = nullptr, *trav;
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  TRACE("name %s: freeing soinfo @ %p", si->name, si);
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (trav = solist; trav != nullptr; trav = trav->next) {
3176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (trav == si) {
3186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    prev = trav;
3216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
322ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
3236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (trav == nullptr) {
3246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // si was not in solist
3255ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov    DL_ERR("name \"%s\"@%p is not in solist!", si->name, si);
3266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
3276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // clear links to/from si
3306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->remove_all_links();
331d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // prev will never be null, because the first entry in solist is
3336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // always the static libdl_info.
3346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  prev->next = si->next;
3356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == sonext) {
3366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    sonext = prev;
3376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
338d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
3396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  g_soinfo_allocator.free(si);
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
342cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_path(const char* path, const char* delimiters,
343cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes                       const char** array, char* buf, size_t buf_size, size_t max_count) {
344851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (path == nullptr) {
345cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    return;
346cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
347cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
348cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  size_t len = strlcpy(buf, path, buf_size);
349cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
350cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  size_t i = 0;
351cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  char* buf_p = buf;
352cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
353cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    if (*array[i] != '\0') {
354cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      ++i;
355cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    }
356cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
357cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
358cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // Forget the last path if we had to truncate; this occurs if the 2nd to
359cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // last char isn't '\0' (i.e. wasn't originally a delimiter).
360cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
361851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    array[i - 1] = nullptr;
362cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  } else {
363851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    array[i] = nullptr;
364cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
365cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
366cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
367cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_LIBRARY_PATH(const char* path) {
3681728b2396591853345507a063ed6075dfd251706Elliott Hughes  parse_path(path, ":", g_ld_library_paths,
3691728b2396591853345507a063ed6075dfd251706Elliott Hughes             g_ld_library_paths_buffer, sizeof(g_ld_library_paths_buffer), LDPATH_MAX);
370cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
371cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
372cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_PRELOAD(const char* path) {
373cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // We have historically supported ':' as well as ' ' in LD_PRELOAD.
3741728b2396591853345507a063ed6075dfd251706Elliott Hughes  parse_path(path, " :", g_ld_preload_names,
3751728b2396591853345507a063ed6075dfd251706Elliott Hughes             g_ld_preloads_buffer, sizeof(g_ld_preloads_buffer), LDPRELOAD_MAX);
376cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
377cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
3784eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
3794688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// For a given PC, find the .so that it belongs to.
3816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Returns the base address of the .ARM.exidx section
3826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// for that .so, and the number of 8-byte entries
3836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// in that section (via *pcount).
3846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Intended to be called by libc's __gnu_Unwind_Find_exidx().
3866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is exposed via dlfcn.cpp and libdl.so.
388faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
3896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  unsigned addr = (unsigned)pc;
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != 0; si = si->next) {
3926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if ((addr >= si->base) && (addr < (si->base + si->size))) {
3936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *pcount = si->ARM_exidx_count;
3946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return (_Unwind_Ptr)si->ARM_exidx;
3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  *pcount = 0;
3986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return nullptr;
3991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4004688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
40124053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif
4024688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
4036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Here, we only have to provide a callback to iterate across all the
4046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// loaded libraries. gcc_eh does the rest.
405faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesint dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
4066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int rv = 0;
4076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
4086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_phdr_info dl_info;
4096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_addr = si->link_map_head.l_addr;
4106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_name = si->link_map_head.l_name;
4116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phdr = si->phdr;
4126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phnum = si->phnum;
4136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    rv = cb(&dl_info, sizeof(dl_phdr_info), data);
4146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (rv != 0) {
4156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
4186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return rv;
4191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4204688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
421ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::find_symbol_by_name(SymbolName& symbol_name) {
422ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return is_gnu_hash() ? gnu_lookup(symbol_name) : elf_lookup(symbol_name);
423ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
424ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
425ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
426ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
427ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      ELF_ST_BIND(s->st_info) == STB_WEAK) {
428ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    return s->st_shndx != SHN_UNDEF;
429ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
430ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
431ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->name);
432ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
433ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
434ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return false;
435ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
436ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
437ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name) {
438ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t hash = symbol_name.gnu_hash();
439047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  uint32_t h2 = hash >> gnu_shift2_;
4401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
441ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
442047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
443047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
4441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
445ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  // test against bloom filter
446ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
447ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    return nullptr;
448ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
449ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
450ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  // bloom test says "probably yes"...
451047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  uint32_t n = bucket_[hash % nbucket_];
452ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
453ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (n == 0) {
454ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    return nullptr;
455ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
456ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
457ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  do {
458047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* s = symtab_ + n;
459047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    if (((chain_[n] ^ hash) >> 1) == 0 &&
460ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
461ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        is_symbol_global_and_defined(this, s)) {
462ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      return s;
463ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
464047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  } while ((chain_[n++] & 1) == 0);
4651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
466ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return nullptr;
467ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
468ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
469ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::elf_lookup(SymbolName& symbol_name) {
470ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t hash = symbol_name.elf_hash();
471ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
472ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
473047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov             symbol_name.get_name(), name, reinterpret_cast<void*>(base), hash, hash % nbucket_);
474ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
475047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
476047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* s = symtab_ + n;
477ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    if (strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 && is_symbol_global_and_defined(this, s)) {
478ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
479ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov               symbol_name.get_name(), name, reinterpret_cast<void*>(s->st_value),
480ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov               static_cast<size_t>(s->st_size));
481ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      return s;
4821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4830266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
4841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
485aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
486047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov             symbol_name.get_name(), name, reinterpret_cast<void*>(base), hash, hash % nbucket_);
487aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
488851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
4891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
49107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanovsoinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags) {
4920d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  memset(this, 0, sizeof(*this));
4930d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
4940d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  strlcpy(this->name, name, sizeof(this->name));
495ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ = FLAG_NEW_SOINFO;
496047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  version_ = SOINFO_VERSION;
4970d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
498851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (file_stat != nullptr) {
499047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->st_dev_ = file_stat->st_dev;
500047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->st_ino_ = file_stat->st_ino;
501047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->file_offset_ = file_offset;
5020d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  }
503e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
504047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  this->rtld_flags_ = rtld_flags;
5050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov}
5060d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
5076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
508ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::elf_hash() {
509ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (!has_elf_hash_) {
510ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    const unsigned char* name = reinterpret_cast<const unsigned char*>(name_);
511ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    uint32_t h = 0, g;
512ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
513ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    while (*name) {
514ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h = (h << 4) + *name++;
515ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      g = h & 0xf0000000;
516ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h ^= g;
517ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h ^= g >> 24;
518ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
519ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
520ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    elf_hash_ = h;
521ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    has_elf_hash_ = true;
5226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
523ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
524ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return elf_hash_;
525ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
526ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
527ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::gnu_hash() {
528ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (!has_gnu_hash_) {
529ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    uint32_t h = 5381;
530ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    const unsigned char* name = reinterpret_cast<const unsigned char*>(name_);
531ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    while (*name != 0) {
532ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
533ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
534ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
535ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    gnu_hash_ =  h;
536ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    has_gnu_hash_ = true;
537ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
538ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
539ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return gnu_hash_;
5401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
542d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovstatic ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in,
543d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) {
544ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  SymbolName symbol_name(name);
5456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Sym)* s = nullptr;
5466ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
54796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  /* "This element's presence in a shared object library alters the dynamic linker's
54896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * symbol resolution algorithm for references within the library. Instead of starting
54996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * a symbol search with the executable file, the dynamic linker starts from the shared
55096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * object itself. If the shared object fails to supply the referenced symbol, the
55196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * dynamic linker then searches the executable file and other shared objects as usual."
55296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   *
55396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
55496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   *
55596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * Note that this is unlikely since static linker avoids generating
55696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * relocations for -Bsymbolic linked dynamic executables.
55796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   */
558d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (si_from->has_DT_SYMBOLIC) {
559d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->name, name);
560ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    s = si_from->find_symbol_by_name(symbol_name);
5618f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    if (s != nullptr) {
562d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      *si_found_in = si_from;
56396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov    }
56496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  }
56596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov
566d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // 1. Look for it in global_group
567d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (s == nullptr) {
568d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    global_group.visit([&](soinfo* global_si) {
569d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      DEBUG("%s: looking up %s in %s (from global group)", si_from->name, name, global_si->name);
570ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      s = global_si->find_symbol_by_name(symbol_name);
57196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov      if (s != nullptr) {
572d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        *si_found_in = global_si;
573d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        return false;
57496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov      }
575c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
576d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      return true;
577d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    });
57896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  }
579c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
580d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // 2. Look for it in the local group
581cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (s == nullptr) {
582cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    local_group.visit([&](soinfo* local_si) {
583d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
584e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov        // we already did this - skip
585e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov        return true;
586e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov      }
587e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov
588d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      DEBUG("%s: looking up %s in %s (from local group)", si_from->name, name, local_si->name);
589ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      s = local_si->find_symbol_by_name(symbol_name);
590cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      if (s != nullptr) {
591d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        *si_found_in = local_si;
592cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov        return false;
593cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      }
5946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
595cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return true;
596cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    });
597cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
598cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
5996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (s != nullptr) {
6006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
6016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov               "found in %s, base = %p, load bias = %p",
602d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov               si_from->name, name, reinterpret_cast<void*>(s->st_value),
603d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov               (*si_found_in)->name, reinterpret_cast<void*>((*si_found_in)->base),
604d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov               reinterpret_cast<void*>((*si_found_in)->load_bias));
6056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
6066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
6078f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov  return s;
6086ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
6096ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
6100cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator.
6110cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
6120cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator {
6130cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
6140cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void* alloc() {
6150cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return allocator_.alloc();
6160cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
6170cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
6180cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(void* ptr) {
6190cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    allocator_.free(ptr);
6200cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
6214bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov
6220cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private:
6230cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static LinkerBlockAllocator allocator_;
6240cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
6250cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
6260cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
6270cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
6280cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
6290cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T>
6300cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator {
6310cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
6320cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static T* alloc() {
6330cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
6340cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
6350cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
6360cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(T* ptr) {
6370cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    SizeBasedAllocator<sizeof(T)>::free(ptr);
6380cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
6390cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
6400cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
64114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask {
64214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public:
64314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct deleter_t {
64414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    void operator()(LoadTask* t) {
64514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      TypeBasedAllocator<LoadTask>::free(t);
64614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
64714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  };
648a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
64914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef UniquePtr<LoadTask, deleter_t> unique_ptr;
650d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom
65114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static deleter_t deleter;
65214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
65314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static LoadTask* create(const char* name, soinfo* needed_by) {
65414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
65514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return new (ptr) LoadTask(name, needed_by);
656aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
657a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
65814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* get_name() const {
65914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return name_;
660a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
66114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
66214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* get_needed_by() const {
66314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return needed_by_;
66414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
66514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private:
66614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTask(const char* name, soinfo* needed_by)
66714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    : name_(name), needed_by_(needed_by) {}
66814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
66914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* name_;
67014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* needed_by_;
67114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
67214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
673aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov};
674aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
675e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng JianLoadTask::deleter_t LoadTask::deleter;
676e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian
67714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T>
67814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
67914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
68014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList;
68114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList;
68214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<LoadTask> LoadTaskList;
68314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
68414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
685cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// This function walks down the tree of soinfo dependencies
686cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// in breadth-first order and
687cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//   * calls action(soinfo* si) for each node, and
688cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//   * terminates walk if action returns false.
689cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//
690cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// walk_dependencies_tree returns false if walk was terminated
691cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// by the action and true otherwise.
692cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovtemplate<typename F>
693cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovstatic bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
6940cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visit_list;
6950cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visited;
6960cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
697cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  for (size_t i = 0; i < root_soinfos_size; ++i) {
698cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    visit_list.push_back(root_soinfos[i]);
699cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
700cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
701cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  soinfo* si;
702cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  while ((si = visit_list.pop_front()) != nullptr) {
703cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (visited.contains(si)) {
704042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov      continue;
705042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov    }
706042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov
707cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (!action(si)) {
708cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return false;
709aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    }
710aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
711cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    visited.push_back(si);
712cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
713cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    si->get_children().for_each([&](soinfo* child) {
714aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov      visit_list.push_back(child);
715aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    });
716aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
717aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
718cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return true;
719cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
720cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
721cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
722cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// This is used by dlsym(3).  It performs symbol lookup only within the
723cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// specified soinfo object and its dependencies in breadth first order.
724cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
725cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ElfW(Sym)* result = nullptr;
726ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  SymbolName symbol_name(name);
727cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
728cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
729cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) {
730ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    result = current_soinfo->find_symbol_by_name(symbol_name);
731cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (result != nullptr) {
732cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      *found = current_soinfo;
733cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return false;
734cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    }
735cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
736cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
737cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
738cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
739cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return result;
7401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
742d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the
743d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   start value is null (for RTLD_DEFAULT), the search starts at the
744d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   beginning of the global solist. Otherwise the search starts at the
745d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   specified soinfo (for RTLD_NEXT).
7466ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
74702aa70589d22fa9b65da43de705d6de2715870c6Dmitriy IvanovElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
748ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  SymbolName symbol_name(name);
7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
750851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (start == nullptr) {
751cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    start = solist;
752cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
7531698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer
754851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  ElfW(Sym)* s = nullptr;
755851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
756e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
757e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov      continue;
758e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    }
759e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
760ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    s = si->find_symbol_by_name(symbol_name);
761851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    if (s != nullptr) {
762cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      *found = si;
763cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      break;
7641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
765cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
7661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
767851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (s != nullptr) {
768c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
769c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes               name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
770cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
7711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
772cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  return s;
7731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
775fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) {
7760266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
777851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
778fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (address >= si->base && address - si->base < si->size) {
779fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return si;
780e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
781fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
782851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
783e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
784e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
785ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
786ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
787ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
788ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
789ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
790ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return sym->st_shndx != SHN_UNDEF &&
791ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      soaddr >= sym->st_value &&
792ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      soaddr < sym->st_value + sym->st_size;
793ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
794ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
795ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
796ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - base;
797ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
798047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (size_t i = 0; i < nbucket_; ++i) {
799047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    uint32_t n = bucket_[i];
800ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
801ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    if (n == 0) {
802ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      continue;
803ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
804ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
805ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    do {
806047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      ElfW(Sym)* sym = symtab_ + n;
807ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      if (symbol_matches_soaddr(sym, soaddr)) {
808ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        return sym;
809ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      }
810047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    } while ((chain_[n++] & 1) == 0);
811ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
812ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
813ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return nullptr;
814ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
815ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
816ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
817ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - base;
818fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
819fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // Search the library's symbol table for any defined symbol which
820fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // contains this address.
821047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (size_t i = 0; i < nchain_; ++i) {
822047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* sym = symtab_ + i;
823ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    if (symbol_matches_soaddr(sym, soaddr)) {
824fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return sym;
825e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
826fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
827e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
828851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
829e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
830e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
831124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library_on_path(const char* name, const char* const paths[]) {
8329fb216f844bb15c8e8f27c5ac0490a2f6faacb57Dmitriy Ivanov  char buf[512];
833851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (size_t i = 0; paths[i] != nullptr; ++i) {
8341e980b6bc8315d00a07312b25486531247abd98cElliott Hughes    int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
835124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
836ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes      PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name);
837124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes      continue;
8381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
839124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
840124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    if (fd != -1) {
841124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes      return fd;
842124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    }
843124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
844124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  return -1;
8451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
847124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library(const char* name) {
848ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ opening %s ]", name);
8491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
850124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // If the name contains a slash, we should attempt to open it directly and not search the paths.
851851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (strchr(name, '/') != nullptr) {
8526971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
8536971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    if (fd != -1) {
8546971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes      return fd;
8556971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    }
8566971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now.
8575ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#if defined(__LP64__)
858e43c4a7a665032a29cb5ec15d4adbf81ea199220Dmitriy Ivanov    return -1;
8595ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#endif
860124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
8611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
862124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
8631728b2396591853345507a063ed6075dfd251706Elliott Hughes  int fd = open_library_on_path(name, g_ld_library_paths);
864124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  if (fd == -1) {
8651728b2396591853345507a063ed6075dfd251706Elliott Hughes    fd = open_library_on_path(name, kDefaultLdPaths);
866124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
867124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  return fd;
8681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
87014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F>
87114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) {
87214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
87314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (d->d_tag == DT_NEEDED) {
8746cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      action(si->get_string(d->d_un.d_val));
875d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    }
87614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
87714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
878d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
879e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
88014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  int fd = -1;
88107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  off64_t file_offset = 0;
88214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ScopedFd file_guard(-1);
883d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
88414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
88514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    fd = extinfo->library_fd;
886a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
887a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov      file_offset = extinfo->library_fd_offset;
88807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    }
88914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  } else {
89014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // Open the file.
89114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    fd = open_library(name);
89214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (fd == -1) {
89314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      DL_ERR("library \"%s\" not found", name);
894498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov      return nullptr;
895498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov    }
896b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
89714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    file_guard.reset(fd);
89814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
89923363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner
90007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if ((file_offset % PAGE_SIZE) != 0) {
901a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov    DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
90207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    return nullptr;
90307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  }
90416f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  if (file_offset < 0) {
90516f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
90616f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    return nullptr;
90716f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  }
90807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
90914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct stat file_stat;
91014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
911a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov    DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
91214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
91314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
91416f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  if (file_offset >= file_stat.st_size) {
91516f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64, name, file_offset, file_stat.st_size);
91616f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    return nullptr;
91716f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  }
918d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
91914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Check for symlink and other situations where
92014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // file can have different names.
92114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
92214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (si->get_st_dev() != 0 &&
92314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        si->get_st_ino() != 0 &&
92414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        si->get_st_dev() == file_stat.st_dev &&
92507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov        si->get_st_ino() == file_stat.st_ino &&
92607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov        si->get_file_offset() == file_offset) {
92714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name);
92814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      return si;
929498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov    }
93014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
931d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
932e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if ((rtld_flags & RTLD_NOLOAD) != 0) {
933a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov    DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
93414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
93514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
936a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
93714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Read the ELF header and load the segments.
93807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  ElfReader elf_reader(name, fd, file_offset);
93914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!elf_reader.Load(extinfo)) {
94014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
94114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
942d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
94307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags);
94414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (si == nullptr) {
94514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
94614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
94714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->base = elf_reader.load_start();
94814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->size = elf_reader.load_size();
94914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->load_bias = elf_reader.load_bias();
95014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phnum = elf_reader.phdr_count();
95114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phdr = elf_reader.loaded_phdr();
95214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
953047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (!si->prelink_image()) {
95414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo_free(si);
95514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
95614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
957a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
95814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for_each_dt_needed(si, [&] (const char* name) {
95914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, si));
96014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
96114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
96214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
9631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
965489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanovstatic soinfo *find_loaded_library_by_name(const char* name) {
966489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  const char* search_name = SEARCH_NAME(name);
967851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
968489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov    if (!strcmp(search_name, si->name)) {
969489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov      return si;
97012c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel    }
971489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  }
972851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
97312c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel}
97412c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel
975e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
976d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
977489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  soinfo* si = find_loaded_library_by_name(name);
978b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
979b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // Library might still be loaded, the accurate detection
98014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // of this fact is done by load_library.
981851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (si == nullptr) {
982b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov    TRACE("[ '%s' has not been found by name.  Trying harder...]", name);
983e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    si = load_library(load_tasks, name, rtld_flags, extinfo);
984b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  }
985b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
98614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
98714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
98814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
98914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si);
99014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
991d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// TODO: this is slightly unusual way to construct
992d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// the global group for relocation. Not every RTLD_GLOBAL
993d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// library is included in this group for backwards-compatibility
994d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// reasons.
995d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov//
996d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// This group consists of the main executable, LD_PRELOADs
997d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// and libraries with the DF_1_GLOBAL flag set.
998d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovstatic soinfo::soinfo_list_t make_global_group() {
999d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  soinfo::soinfo_list_t global_group;
1000d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  for (soinfo* si = somain; si != nullptr; si = si->next) {
1001d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1002d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      global_group.push_back(si);
1003d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
1004d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
1005d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1006d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return global_group;
1007d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
1008d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1009cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovstatic bool find_libraries(soinfo* start_with, const char* const library_names[], size_t library_names_count, soinfo* soinfos[],
1010cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    soinfo* ld_preloads[], size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) {
101114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 0: prepare.
101214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTaskList load_tasks;
1013cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  for (size_t i = 0; i < library_names_count; ++i) {
101414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    const char* name = library_names[i];
1015cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, start_with));
1016cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
1017cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1018d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // Construct global_group.
1019d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  soinfo::soinfo_list_t global_group = make_global_group();
1020d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1021cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // If soinfos array is null allocate one on stack.
1022cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // The array is needed in case of failure; for example
1023cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // when library_names[] = {libone.so, libtwo.so} and libone.so
1024cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // is loaded correctly but libtwo.so failed for some reason.
1025cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // In this case libone.so should be unloaded on return.
1026cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // See also implementation of failure_guard below.
1027cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1028cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (soinfos == nullptr) {
1029cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1030cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1031cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    memset(soinfos, 0, soinfos_size);
103214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
103314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1034cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // list of libraries to link - see step 2.
1035cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  size_t soinfos_count = 0;
103614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1037d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto failure_guard = make_scope_guard([&]() {
103814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // Housekeeping
103914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.for_each([] (LoadTask* t) {
104014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      LoadTask::deleter(t);
104114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    });
104214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1043cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    for (size_t i = 0; i<soinfos_count; ++i) {
104414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      soinfo_unload(soinfos[i]);
104514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
104614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
104714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
104814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
104914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) {
1050e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
105114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (si == nullptr) {
105214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      return false;
105314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
105414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
105514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* needed_by = task->get_needed_by();
105614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
105714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (needed_by != nullptr) {
105814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      needed_by->add_child(si);
105914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
106014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1061ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (si->is_linked()) {
1062ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->increment_ref_count();
1063ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1064ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1065cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    // When ld_preloads is not null, the first
1066cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    // ld_preloads_count libs are in fact ld_preloads.
1067cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
1068d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // Add LD_PRELOADed libraries to the global group for future runs.
1069d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // There is no need to explicitly add them to the global group
1070d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // for this run because they are going to appear in the local
1071d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // group in the correct order.
1072d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1073cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      ld_preloads[soinfos_count] = si;
107414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
107514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1076cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (soinfos_count < library_names_count) {
1077cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      soinfos[soinfos_count++] = si;
107814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
107914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
108014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
108114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 2: link libraries.
1082cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  soinfo::soinfo_list_t local_group;
1083cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  walk_dependencies_tree(
1084cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      start_with == nullptr ? soinfos : &start_with,
1085cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      start_with == nullptr ? soinfos_count : 1,
1086cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      [&] (soinfo* si) {
1087cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    local_group.push_back(si);
1088cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
1089cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
1090cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1091ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // We need to increment ref_count in case
1092ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // the root of the local group was not linked.
1093ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  bool was_local_group_root_linked = local_group.front()->is_linked();
1094ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1095cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  bool linked = local_group.visit([&](soinfo* si) {
1096ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (!si->is_linked()) {
1097047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      if (!si->link_image(global_group, local_group, extinfo)) {
109814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        return false;
109914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      }
1100ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->set_linked();
110114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
1102cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1103cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
1104cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
1105cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1106cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (linked) {
1107cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    failure_guard.disable();
1108a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
110914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1110ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!was_local_group_root_linked) {
1111ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_group.front()->increment_ref_count();
1112ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
1113ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1114cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return linked;
111514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
111614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1117e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
111814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* si;
111914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1120ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (name == nullptr) {
1121ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    si = somain;
1122ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
112314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
112414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
112514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1126d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
1127d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
1128d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1129ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovstatic void soinfo_unload(soinfo* root) {
1130ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // Note that the library can be loaded but not linked;
1131ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // in which case there is no root but we still need
1132ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // to walk the tree and unload soinfos involved.
1133ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
1134ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // This happens on unsuccessful dlopen, when one of
1135ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // the DT_NEEDED libraries could not be linked/found.
1136ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (root->is_linked()) {
1137ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    root = root->get_local_group_root();
11381b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  }
11391b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
1140ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!root->can_unload()) {
1141ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->name);
1142ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    return;
1143ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
1144d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1145ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  size_t ref_count = root->is_linked() ? root->decrement_ref_count() : 0;
1146ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1147ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (ref_count == 0) {
1148ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t local_unload_list;
1149ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t external_unload_list;
1150ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t depth_first_list;
1151ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    depth_first_list.push_back(root);
1152ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo* si = nullptr;
1153ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1154ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = depth_first_list.pop_front()) != nullptr) {
11555ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov      if (local_unload_list.contains(si)) {
11565ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov        continue;
11575ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov      }
11585ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov
1159ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      local_unload_list.push_back(si);
11605ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov
1161ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      if (si->has_min_version(0)) {
1162ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        soinfo* child = nullptr;
1163ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        while ((child = si->get_children().pop_front()) != nullptr) {
11645ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov          TRACE("%s@%p needs to unload %s@%p", si->name, si, child->name, child);
1165ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          if (local_unload_list.contains(child)) {
1166ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            continue;
11675ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov          } else if (child->is_linked() && child->get_local_group_root() != root) {
1168ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            external_unload_list.push_back(child);
1169ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else {
1170ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            depth_first_list.push_front(child);
1171ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          }
1172d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov        }
1173ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      } else {
11745ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#ifdef __LP64__
11755ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov        __libc_fatal("soinfo for \"%s\"@%p has no version", si->name, si);
11765ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#else
11775ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov        PRINT("warning: soinfo for \"%s\"@%p has no version", si->name, si);
1178ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        for_each_dt_needed(si, [&] (const char* library_name) {
1179ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name);
1180ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
1181ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          if (needed != nullptr) {
1182ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // Not found: for example if symlink was deleted between dlopen and dlclose
1183ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // Since we cannot really handle errors at this point - print and continue.
1184ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name);
1185ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            return;
1186ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else if (local_unload_list.contains(needed)) {
1187ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // already visited
1188ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            return;
11895ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov          } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1190ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // external group
1191ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            external_unload_list.push_back(needed);
1192ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else {
1193ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // local group
1194ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            depth_first_list.push_front(needed);
1195ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          }
1196ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        });
11975ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#endif
1198ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      }
11991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1201ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_unload_list.for_each([](soinfo* si) {
1202ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->call_destructors();
1203ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    });
12041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1205ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = local_unload_list.pop_front()) != nullptr) {
1206ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      notify_gdb_of_unload(si);
1207ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      soinfo_free(si);
1208ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1209a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov
1210ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = external_unload_list.pop_front()) != nullptr) {
1211ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      soinfo_unload(si);
1212ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1213ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else {
1214ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    TRACE("not unloading '%s' group, decrementing ref_count to %zd", root->name, ref_count);
1215a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov  }
1216a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov}
1217a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov
1218a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
1219052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Use basic string manipulation calls to avoid snprintf.
1220052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1221052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // When debug malloc is enabled, this call returns 0. This in turn causes
1222052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf to do nothing, which causes libraries to fail to load.
1223052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // See b/17302493 for further details.
1224052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Once the above bug is fixed, this code can be modified to use
1225052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf again.
1226052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
1227052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  if (buffer_size < required_len) {
1228052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: buffer len %zu, required len %zu",
1229052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris                 buffer_size, required_len);
1230052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  }
1231052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  char* end = stpcpy(buffer, kDefaultLdPaths[0]);
1232052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  *end = ':';
1233052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  strcpy(end + 1, kDefaultLdPaths[1]);
1234a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes}
1235a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
1236cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
1237cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  if (!get_AT_SECURE()) {
1238cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    parse_LD_LIBRARY_PATH(ld_library_path);
1239cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
1240cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
1241cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
12421a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughessoinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
12431b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
1244e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes    DL_ERR("invalid flags to dlopen: %x", flags);
1245851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
1246e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  }
124707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if (extinfo != nullptr) {
124807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
124907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
125007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      return nullptr;
125107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    }
125207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
1253a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov        (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1254a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
125507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      return nullptr;
125607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    }
1257012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  }
1258d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ | PROT_WRITE);
12599fb216f844bb15c8e8f27c5ac0490a2f6faacb57Dmitriy Ivanov  soinfo* si = find_library(name, flags, extinfo);
1260851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (si != nullptr) {
1261047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    si->call_constructors();
1262d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1263d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ);
1264d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
1265d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
12661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1267b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid do_dlclose(soinfo* si) {
1268d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ | PROT_WRITE);
1269b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  soinfo_unload(si);
1270d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ);
12711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12739aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
12749aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  typedef ElfW(Addr) (*ifunc_resolver_t)(void);
12759aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
12769aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ElfW(Addr) ifunc_addr = ifunc_resolver();
12779aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
1278c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
12799aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return ifunc_addr;
1280c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
1281c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
12824eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
1283047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovint soinfo::relocate(ElfW(Rela)* rela, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
1284c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes  for (size_t idx = 0; idx < count; ++idx, ++rela) {
12850266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    unsigned type = ELFW(R_TYPE)(rela->r_info);
12860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    unsigned sym = ELFW(R_SYM)(rela->r_info);
128729bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + load_bias);
12880266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    ElfW(Addr) sym_addr = 0;
1289851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    const char* sym_name = nullptr;
1290c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
129129bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov    DEBUG("Processing '%s' relocation at index %zd", name, idx);
1292cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov    if (type == R_GENERIC_NONE) {
1293c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      continue;
1294c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
129514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
129614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    ElfW(Sym)* s = nullptr;
129714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* lsi = nullptr;
129814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1299c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    if (sym != 0) {
1300047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      sym_name = get_string(symtab_[sym].st_name);
1301d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      s = soinfo_do_lookup(this, sym_name, &lsi, global_group,local_group);
1302851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov      if (s == nullptr) {
1303c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We only allow an undefined symbol if this is a weak reference...
1304047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        s = &symtab_[sym];
1305c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
130629bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
1307c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes          return -1;
1308c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1309c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1310c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        /* IHI0044C AAELF 4.5.1.1:
1311c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1312c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           Libraries are not searched to resolve weak references.
1313c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           It is not an error for a weak reference to remain unsatisfied.
1314c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1315c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           During linking, the value of an undefined weak reference is:
1316c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - Zero if the relocation type is absolute
1317c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of the place if the relocation is pc-relative
1318c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of nominal base address if the relocation
1319c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes             type is base-relative.
1320c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes         */
1321c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1322c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        switch (type) {
13231b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_JUMP_SLOT:
13241b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_GLOB_DAT:
13251b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_RELATIVE:
13261b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_IRELATIVE:
1327e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__)
13286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS64:
13296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS32:
13306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS16:
13311b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#elif defined(__x86_64__)
13321b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_X86_64_32:
13331b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_X86_64_64:
13341b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#endif
13356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            /*
13366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * The sym_addr was initialized to be zero above, or the relocation
13376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * code below does not care about value of sym_addr.
13386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * No need to do anything.
13396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             */
13406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
13411b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#if defined(__x86_64__)
1342d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov          case R_X86_64_PC32:
1343d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov            sym_addr = reloc;
1344d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov            break;
1345d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov#endif
13466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          default:
13476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rela, idx);
13486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            return -1;
1349c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1350c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      } else {
1351c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We got a definition.
13529aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov        sym_addr = lsi->resolve_symbol_address(s);
1353c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      }
1354c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      count_relocation(kRelocSymbol);
1355c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
1356c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1357c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    switch (type) {
1358cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_JUMP_SLOT:
1359e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1360e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
13610266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO JMP_SLOT %16llx <- %16llx %s\n",
13620266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
13630266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend);
1364e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1365cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_GLOB_DAT:
1366e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1367e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
13680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO GLOB_DAT %16llx <- %16llx %s\n",
13690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
13700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend);
1371e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1372cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_RELATIVE:
1373cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1374cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        MARK(rela->r_offset);
1375cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        if (sym) {
1376cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          DL_ERR("error: encountered _RELATIVE relocation with a symbol");
1377cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          return -1;
1378cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        }
1379cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n",
1380cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov                   reloc, (base + rela->r_addend));
1381cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (base + rela->r_addend);
1382cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1383cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1384cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_IRELATIVE:
1385cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1386cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        MARK(rela->r_offset);
1387cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend));
1388cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + rela->r_addend);
1389cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1390cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1391cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__aarch64__)
13926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS64:
1393e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1394e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
13950266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
13960266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
13970266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend);
1398e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
13996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS32:
1400e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1401e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
14020266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
14030266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
14040266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) &&
14050266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) {
14066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend);
1407e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
14086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
14096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)),
14106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT32_MIN),
14116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT32_MAX));
14126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1413e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1414e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
14156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS16:
1416e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1417e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
14180266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
14190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), sym_name);
14200266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) &&
14210266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) {
14226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend);
1423e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
14246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
14256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)),
14266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT16_MIN),
14276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT16_MAX));
14286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1429e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1430e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
14316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL64:
1432e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1433e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
14340266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
14350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name);
14360266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend) - rela->r_offset;
1437e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
14386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL32:
1439e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1440e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
14410266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
14420266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name);
14430266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) &&
14440266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) {
14456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset);
1446e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
14476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
14486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)),
14496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT32_MIN),
14506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT32_MAX));
14516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1452e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1453e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
14546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL16:
1455e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1456e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        MARK(rela->r_offset);
14570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
14580266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name);
14590266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) &&
14600266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes            ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) {
14616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset);
1462e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        } else {
14636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
14646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)),
14656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(INT16_MIN),
14666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 static_cast<ElfW(Addr)>(UINT16_MAX));
14676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1468e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1469e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1470e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
14716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_COPY:
147276e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich        /*
147376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * ET_EXEC is not supported so this should not happen.
147476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
147576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
147676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
147776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * Section 4.7.1.10 "Dynamic relocations"
147876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * R_AARCH64_COPY may only appear in executable objects where e_type is
147976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * set to ET_EXEC.
148076e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         */
148129bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov        DL_ERR("%s R_AARCH64_COPY relocations are not supported", name);
148276e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich        return -1;
14836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_TPREL64:
14840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
14850266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset);
1486e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
14876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_DTPREL32:
14880266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
14890266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes                   reloc, (sym_addr + rela->r_addend), rela->r_offset);
1490e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1491e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__)
14926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_32:
14936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
14946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
14956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
14966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
14976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
14986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
14996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_64:
15006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
15016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
15026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
15036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
15046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
15056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
15066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_PC32:
15076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
15086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rela->r_offset);
15096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
15106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
15116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
1512d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend - reloc;
15136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
15144eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
1515e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
15166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
15176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rela, idx);
15186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return -1;
1519c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
1520c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes  }
1521c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes  return 0;
1522c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes}
15239918665a45095ad135576f005c0e5307feb366a1Chris Dearman
15249918665a45095ad135576f005c0e5307feb366a1Chris Dearman#else // REL, not RELA.
1525047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovint soinfo::relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
15266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t idx = 0; idx < count; ++idx, ++rel) {
15276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned type = ELFW(R_TYPE)(rel->r_info);
15286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead.
15296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned sym = ELFW(R_SYM)(rel->r_info);
15306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
15316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ElfW(Addr) sym_addr = 0;
15326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    const char* sym_name = nullptr;
15336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
15346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("Processing '%s' relocation at index %zd", name, idx);
1535cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov    if (type == R_GENERIC_NONE) {
15366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
15376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
15386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
15396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ElfW(Sym)* s = nullptr;
15406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    soinfo* lsi = nullptr;
15416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
15426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (sym != 0) {
1543047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      sym_name = get_string(symtab_[sym].st_name);
1544d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group);
15456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (s == nullptr) {
15466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // We only allow an undefined symbol if this is a weak reference...
1547047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        s = &symtab_[sym];
15486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
15496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
15506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
1551d7daacb46372132ae3f0121647074936c304b572Raghu Gandham        }
155214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
15536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        /* IHI0044C AAELF 4.5.1.1:
15546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
15556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           Libraries are not searched to resolve weak references.
15566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           It is not an error for a weak reference to remain
15576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           unsatisfied.
15586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
15596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           During linking, the value of an undefined weak reference is:
15606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           - Zero if the relocation type is absolute
15616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           - The address of the place if the relocation is pc-relative
15626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           - The address of nominal base address if the relocation
15636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             type is base-relative.
15646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        */
15656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
15666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        switch (type) {
1567cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if !defined(__mips__)
1568cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          case R_GENERIC_JUMP_SLOT:
1569cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          case R_GENERIC_GLOB_DAT:
1570cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          case R_GENERIC_RELATIVE:
1571cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          case R_GENERIC_IRELATIVE:
1572cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#endif
1573cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
15744eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
1575cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          case R_ARM_ABS32:    /* Don't care. */
15766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // sym_addr was initialized to be zero above or relocation
15776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // code below does not care about value of sym_addr.
15786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // No need to do anything.
15796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
15804eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
15816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_32:
15826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // sym_addr was initialized to be zero above or relocation
15836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // code below does not care about value of sym_addr.
15846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            // No need to do anything.
15856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
15866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_386_PC32:
15876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            sym_addr = reloc;
15886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
15894eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
15906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          default:
15916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
15926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            return -1;
15931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
15946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      } else {
15956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // We got a definition.
15966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        sym_addr = lsi->resolve_symbol_address(s);
15976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
15986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      count_relocation(kRelocSymbol);
15996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
16001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    switch (type) {
1602cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if !defined(__mips__)
1603cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_JUMP_SLOT:
16046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
16056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
16066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
16076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
16086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
1609cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1610cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_GLOB_DAT:
16116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
16126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
16136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
16146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
16156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
1616cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1617cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_RELATIVE:
1618cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1619cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        MARK(rel->r_offset);
1620cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        if (sym) {
1621cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          DL_ERR("odd RELATIVE form...");
1622cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov          return -1;
1623cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        }
1624cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p",
1625cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov                   reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
1626cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
1627cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1628cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1629cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_IRELATIVE:
1630cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1631cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        MARK(rel->r_offset);
1632cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
1633cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + *reinterpret_cast<ElfW(Addr)*>(reloc));
1634cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1635cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#endif
1636cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1637cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__arm__)
16386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_ABS32:
16396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
16406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
16416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
16426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
16436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
16446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_REL32:
16456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
16466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
16476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
16486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, sym_addr, rel->r_offset, sym_name);
16496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
16506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
16516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_COPY:
16526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        /*
16536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * ET_EXEC is not supported so this should not happen.
16546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
16556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
16566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
16576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * Section 4.7.1.10 "Dynamic relocations"
16586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * R_ARM_COPY may only appear in executable objects where e_type is
16596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * set to ET_EXEC.
16606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         */
16616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("%s R_ARM_COPY relocations are not supported", name);
16626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return -1;
16634eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
16646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_32:
16656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
16666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
16676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
16686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
16696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
16706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_PC32:
16716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
16726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
16736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
16746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
16756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
16766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
16774eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__mips__)
16786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_MIPS_REL32:
16799918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if defined(__LP64__)
16806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // MIPS Elf64_Rel entries contain compound relocations
16816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case
16826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 ||
16836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) {
16846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)",
16856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 type, (unsigned)ELF64_R_TYPE2(rel->r_info),
16866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                 (unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx);
16876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return -1;
16886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
16899918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif
16906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
16916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
16926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc),
16936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*");
16946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (s) {
16956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
16966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        } else {
16976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
16986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
16996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
17004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
17014eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes
17026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
17036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
17046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return -1;
17051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
17076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return 0;
17081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1709c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
17101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17114eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
1712889409168322920ab6cddeb93f506c983d8b5878Dmitriy Ivanovbool soinfo::mips_relocate_got(const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
1713047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  ElfW(Addr)** got = plt_got_;
17146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (got == nullptr) {
17156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return true;
17166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
17176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
17186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // got[0] is the address of the lazy resolver function.
17196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // got[1] may be used for a GNU extension.
17206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Set it to a recognizable address in case someone calls it (should be _rtld_bind_start).
17216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // FIXME: maybe this should be in a separate routine?
172220463e3e53d6e9e23a7267e08da0e01bf8780fdeDmitriy Ivanov  if ((flags_ & FLAG_LINKER) == 0) {
17236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    size_t g = 0;
17246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadbeef);
17256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (reinterpret_cast<intptr_t>(got[g]) < 0) {
17266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadfeed);
172787c358524e479235aa6241736d2ce325f89daafcBrian Carlstrom    }
17286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // Relocate the local GOT entries.
1729047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    for (; g < mips_local_gotno_; g++) {
1730889409168322920ab6cddeb93f506c983d8b5878Dmitriy Ivanov      got[g] = reinterpret_cast<ElfW(Addr)*>(reinterpret_cast<uintptr_t>(got[g]) + load_bias);
1731d7daacb46372132ae3f0121647074936c304b572Raghu Gandham    }
17326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1733d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
17346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Now for the global GOT entries...
1735047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  ElfW(Sym)* sym = symtab_ + mips_gotsym_;
1736047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  got = plt_got_ + mips_local_gotno_;
1737047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (size_t g = mips_gotsym_; g < mips_symtabno_; g++, sym++, got++) {
17386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // This is an undefined reference... try to locate it.
1739889409168322920ab6cddeb93f506c983d8b5878Dmitriy Ivanov    const char* sym_name = get_string(sym->st_name);
17406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    soinfo* lsi = nullptr;
1741889409168322920ab6cddeb93f506c983d8b5878Dmitriy Ivanov    ElfW(Sym)* s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group);
17426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (s == nullptr) {
17436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      // We only allow an undefined symbol if this is a weak reference.
1744047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      s = &symtab_[g];
17456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
17466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("cannot locate \"%s\"...", sym_name);
17476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
17486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
17496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      *got = 0;
17506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    } else {
17516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      // FIXME: is this sufficient?
17526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      // For reference see NetBSD link loader
17536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy 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
17546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      *got = reinterpret_cast<ElfW(Addr)*>(lsi->resolve_symbol_address(s));
1755d7daacb46372132ae3f0121647074936c304b572Raghu Gandham    }
17566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
17576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
1758d7daacb46372132ae3f0121647074936c304b572Raghu Gandham}
1759d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif
1760d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
1761047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_array(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) {
1762851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (functions == nullptr) {
1763d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
1764d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
17658215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1766c620059479c47a78d57086d73726c9adc2f337adElliott Hughes  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, name);
17678215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1768ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int begin = reverse ? (count - 1) : 0;
1769ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int end = reverse ? -1 : count;
1770ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int step = reverse ? -1 : 1;
17718215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1772ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  for (int i = begin; i != end; i += step) {
1773ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
1774047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    call_function("function", functions[i]);
1775d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1776d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1777ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ Done calling %s for '%s' ]", array_name, name);
17781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
17791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1780047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_function(const char* function_name __unused, linker_function_t function) {
1781851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
1782d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
1783d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1784d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1785ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, name);
1786d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  function();
1787ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, name);
1788db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes
1789db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes  // The function may have called dlopen(3) or dlclose(3), so we need to ensure our data structures
1790db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes  // are still writable. This happens with our debug malloc (see http://b/7941716).
1791d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ | PROT_WRITE);
17929181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov}
17939181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
1794047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_pre_init_constructors() {
17958147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
17968147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // but ignored in a shared library.
1797047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false);
1798d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
1799e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
1800047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_constructors() {
1801d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  if (constructors_called) {
1802d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
1803d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1804e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
1805d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // We set constructors_called before actually calling the constructors, otherwise it doesn't
1806d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // protect against recursive constructor calls. One simple example of constructor recursion
1807d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
1808d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 1. The program depends on libc, so libc's constructor is called here.
1809d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
1810d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 3. dlopen() calls the constructors on the newly created
1811d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    soinfo for libc_malloc_debug_leak.so.
1812d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 4. The debug .so depends on libc, so CallConstructors is
1813d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    called again with the libc soinfo. If it doesn't trigger the early-
1814d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    out above, the libc constructor will be called again (recursively!).
1815d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  constructors_called = true;
1816d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1817ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!is_main_executable() && preinit_array_ != nullptr) {
18188147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes    // The GNU dynamic linker silently ignores these, but we warn the developer.
1819c620059479c47a78d57086d73726c9adc2f337adElliott Hughes    PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
1820047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov          name, preinit_array_count_);
1821d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1823d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  get_children().for_each([] (soinfo* si) {
1824047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    si->call_constructors();
1825d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
18261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18278147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  TRACE("\"%s\": calling constructors", name);
18288147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
18298147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_INIT should be called before DT_INIT_ARRAY if both are present.
1830047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_INIT", init_func_);
1831047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false);
1832e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov}
18338215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
1834047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_destructors() {
183514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!constructors_called) {
183614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return;
183714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
18388147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  TRACE("\"%s\": calling destructors", name);
18398147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
18408147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI_ARRAY must be parsed in reverse order.
1841047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
18428147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
18438147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI should be called after DT_FINI_ARRAY if both are present.
1844047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_FINI", fini_func_);
1845b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
1846b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // This is needed on second call to dlopen
1847b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // after library has been unloaded with RTLD_NODELETE
1848b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  constructors_called = false;
18491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
18501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1851d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) {
18520d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
1853047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.push_back(this);
1854047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->children_.push_back(child);
1855d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1856d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1857d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1858d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() {
18590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (!has_min_version(0)) {
1860d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    return;
1861d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1862d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1863d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 1. Untie connected soinfos from 'this'.
1864047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.for_each([&] (soinfo* child) {
1865047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.remove_if([&] (const soinfo* parent) {
1866d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return parent == this;
1867d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
1868d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
1869d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1870047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.for_each([&] (soinfo* parent) {
1871047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    parent->children_.remove_if([&] (const soinfo* child) {
1872d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return child == this;
1873d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
1874d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
1875d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1876d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 2. Once everything untied - clear local lists.
1877047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.clear();
1878047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.clear();
1879d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1880d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1881d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovdev_t soinfo::get_st_dev() const {
18820d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
1883047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_dev_;
1884d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1885d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
18860d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
1887d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov};
1888d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1889d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovino_t soinfo::get_st_ino() const {
18900d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
1891047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_ino_;
1892d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1893d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
18940d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
1895d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1896d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1897d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovoff64_t soinfo::get_file_offset() const {
189807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if (has_min_version(1)) {
1899047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return file_offset_;
190007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  }
190107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
190207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  return 0;
190307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov}
190407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
1905d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_rtld_flags() const {
1906e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if (has_min_version(1)) {
1907047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return rtld_flags_;
1908e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  }
1909e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
1910e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  return 0;
1911e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
1912e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
1913d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_dt_flags_1() const {
1914d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
1915047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return dt_flags_1_;
1916d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
1917d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1918d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return 0;
1919d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
1920d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovvoid soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
1921d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
1922d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
1923047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_GLOBAL;
1924d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
1925d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1926d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_NODELETE) != 0) {
1927047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_NODELETE;
1928d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
1929d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1930047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    dt_flags_1_ = dt_flags_1;
1931d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
1932d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
1933d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
193414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if
1935d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set.
1936d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list;
1937d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1938d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() {
19390d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
1940047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return children_;
1941d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
1942d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
19430d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return g_empty_list;
1944d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
1945d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
194614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() {
1947047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(0)) {
1948047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return parents_;
194914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
195014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1951047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return g_empty_list;
195214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
195314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
19549aea164457c269c475592da36b4655d45f55c7bcDmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) {
19559aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
19569aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov    return call_ifunc_resolver(s->st_value + load_bias);
19579aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  }
19589aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
19599aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return static_cast<ElfW(Addr)>(s->st_value + load_bias);
19609aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov}
19619aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
19626cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const {
1963047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(1) && (index >= strtab_size_)) {
1964047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", name, strtab_size_, index);
19656cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov  }
19666cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
1967047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return strtab_ + index;
19686cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov}
19696cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
1970ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovbool soinfo::is_gnu_hash() const {
1971ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_GNU_HASH) != 0;
1972ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1973ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
19741b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const {
1975d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
19761b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
1977d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1978ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_linked() const {
1979ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_LINKED) != 0;
1980ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
1981ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1982ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_main_executable() const {
1983ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_EXE) != 0;
1984ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
1985ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1986ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linked() {
1987ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKED;
1988ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
1989ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1990ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linker_flag() {
1991ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKER;
1992ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
1993ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1994ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_main_executable() {
1995ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_EXE;
1996ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
1997ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1998ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::increment_ref_count() {
1999ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_->ref_count_++;
2000ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2001ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2002ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsize_t soinfo::decrement_ref_count() {
2003ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return --local_group_root_->ref_count_;
2004ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2005ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2006ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsoinfo* soinfo::get_local_group_root() const {
2007ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return local_group_root_;
2008ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2009ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
20101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with
20111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   /dev/null. */
20125419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic int nullify_closed_stdio() {
20136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int dev_null, i, status;
20146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int return_value = 0;
20151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
20176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dev_null < 0) {
20186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("cannot open /dev/null: %s", strerror(errno));
20196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return -1;
20206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null);
20226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
20236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* If any of the stdio file descriptors is valid and not associated
20246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov     with /dev/null, dup /dev/null to it.  */
20256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (i = 0; i < 3; i++) {
20266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* If it is /dev/null already, we are done. */
20276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (i == dev_null) {
20286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
20291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
20301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE("[ Nullifying stdio file descriptor %d]", i);
20326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
20331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* If file is opened, we are good. */
20356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status != -1) {
20366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
20376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
20381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* The only error we allow is that the file descriptor does not
20406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       exist, in which case we dup /dev/null to it. */
20416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (errno != EBADF) {
20426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("fcntl failed: %s", strerror(errno));
20436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
20446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
20456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
20461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* Try dupping /dev/null to this stdio file descriptor and
20486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       repeat if there is a signal.  Note that any errors in closing
20496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       the stdio descriptor are lost.  */
20506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
20516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status < 0) {
20526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("dup2 failed: %s", strerror(errno));
20536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
20546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
20551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
20566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* If /dev/null is not one of the stdio file descriptors, close it. */
20596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dev_null > 2) {
20606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null);
20616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(close(dev_null));
20626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status == -1) {
20636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("close failed: %s", strerror(errno));
20646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
20651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
20666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return return_value;
20691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
20701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2071047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::prelink_image() {
2072e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  /* Extract dynamic section */
2073e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  ElfW(Word) dynamic_flags = 0;
2074e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
2075498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov
20766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can't log anything until the linker is relocated */
2077ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
20786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!relocating_linker) {
20796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    INFO("[ linking %s ]", name);
2080ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
20816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
20826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
20836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dynamic == nullptr) {
2084b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    if (!relocating_linker) {
20856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("missing PT_DYNAMIC in \"%s\"", name);
2086b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    }
20876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
20886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
20896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (!relocating_linker) {
20906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DEBUG("dynamic = %p", dynamic);
209163f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner    }
20926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
209363f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
20944eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
20956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
20966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                  &ARM_exidx, &ARM_exidx_count);
209763f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif
209863f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
20996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract useful information from dynamic section.
21006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  uint32_t needed_count = 0;
21016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
21026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
21036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
21046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    switch (d->d_tag) {
21054a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SONAME:
21064a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // TODO: glibc dynamic linker uses this name for
21074a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // initial library lookup; consider doing the same here.
21084a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2109ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_HASH:
2111047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        if (nbucket_ != 0) {
2112ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          // in case of --hash-style=both, we prefer gnu
2113ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          break;
2114ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        }
2115ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2116047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2117047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2118047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2119047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
21206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2121ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2122ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      case DT_GNU_HASH:
2123047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        if (nbucket_ != 0) {
2124ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          // in case of --hash-style=both, we prefer gnu
2125047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov          nchain_ = 0;
2126ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        }
2127ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2128047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2129ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // skip symndx
2130047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2131047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
2132ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2133047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
2134047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
2135ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // amend chain for symndx = header[1]
2136047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        chain_ = bucket_ + nbucket_ - reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2137ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2138047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        if (!powerof2(gnu_maskwords_)) {
2139047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two", gnu_maskwords_, name);
2140ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          return false;
2141ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        }
2142047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        --gnu_maskwords_;
2143ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2144ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        flags_ |= FLAG_GNU_HASH;
2145ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        break;
2146ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
21476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_STRTAB:
2148047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
21496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2150ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21516cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_STRSZ:
2152047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_size_ = d->d_un.d_val;
21536cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
2154ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMTAB:
2156047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
21576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2158ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21594a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SYMENT:
21604a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Sym))) {
2161ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          DL_ERR("invalid DT_SYMENT: %zd in \"%s\"", static_cast<size_t>(d->d_un.d_val), name);
21624a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
21634a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
21644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2165ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTREL:
2167513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA)
2168513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        if (d->d_un.d_val != DT_RELA) {
2169513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", name);
2170513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov          return false;
2171513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        }
2172513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else
21736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val != DT_REL) {
2174513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", name);
21756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
21766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
2177c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
2178513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2179ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_JMPREL:
21814eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2182047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
2183c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2184047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
2185c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
21866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2187ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTRELSZ:
21894eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2190047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
2191c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2192047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
2193c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
21946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2195ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
21966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTGOT:
21974a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__)
21986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Used by mips and mips64.
2199047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
2200c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
22014a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // Ignore for other platforms... (because RTLD_LAZY is not supported)
22024a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2203ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_DEBUG:
22056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_DEBUG entry to the address of _r_debug for GDB
22066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // if the dynamic table is writable
22079918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64
22089918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree.
220914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as
22109918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable.
22119918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__))
22126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if ((dynamic_flags & PF_W) != 0) {
22136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
22146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
22156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
22169918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif
22174eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
22186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
2219047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
22206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2221ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELASZ:
2223047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
22246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2225ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22264a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELAENT:
22274a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rela))) {
2228f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
22294a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
22304a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
22314a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2232ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2233ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // ignored (see DT_RELCOUNT comments for details)
22344a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELACOUNT:
22354a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2236ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
22386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unsupported DT_REL in \"%s\"", name);
22396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2240ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
22426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unsupported DT_RELSZ in \"%s\"", name);
22436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2244c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
22456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
2246047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
22476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2248ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
2250047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
22516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2252ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22534a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELENT:
22544a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rel))) {
2255f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
22564a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
22574a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
22584a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2259ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2260ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // "Indicates that all RELATIVE relocations have been concatenated together,
2261ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // and specifies the RELATIVE relocation count."
2262ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      //
2263ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // TODO: Spec also mentions that this can be used to optimize relocation process;
2264ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Not currently used by bionic linker - ignored.
22654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELCOUNT:
22664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
22676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
22686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unsupported DT_RELA in \"%s\"", name);
22696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2270c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
22716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT:
2272047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2273047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT) found at %p", name, init_func_);
22746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2275ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI:
2277047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2278047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func_);
22796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2280ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAY:
2282047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2283047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array_);
22846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2285ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAYSZ:
2287047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_array_count_ = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
22886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2289ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAY:
2291047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2292047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array_);
22936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2294ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAYSZ:
2296047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_array_count_ = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
22976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2298ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
22996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAY:
2300047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2301047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array_);
23026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2303ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
23046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAYSZ:
2305047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        preinit_array_count_ = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
23066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2307ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
23086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_TEXTREL:
2309e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__)
23106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name);
23116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2312e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else
23136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        has_text_relocations = true;
23146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2315e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
2316ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
23176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMBOLIC:
231896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        has_DT_SYMBOLIC = true;
23196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2320ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
23216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_NEEDED:
23226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        ++needed_count;
23236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2324ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
23256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FLAGS:
23266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val & DF_TEXTREL) {
2327e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__)
23286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name);
23296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
2330e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else
23316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          has_text_relocations = true;
2332e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
23336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
233496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        if (d->d_un.d_val & DF_SYMBOLIC) {
233596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov          has_DT_SYMBOLIC = true;
233696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        }
23376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2338ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
23396cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_FLAGS_1:
2340d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        set_dt_flags_1(d->d_un.d_val);
23416cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2342d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
23436cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov          DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val));
23446cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        }
23456cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
23464eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
23476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_MAP:
23486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
23496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        {
23506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
23516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *dp = &_r_debug;
23526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
23536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2354688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham      case DT_MIPS_RLD_MAP2:
2355688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
2356688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        {
2357688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham          r_debug** dp = reinterpret_cast<r_debug**>(reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
2358688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham          *dp = &_r_debug;
2359688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        }
2360688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        break;
2361ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
23626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_VERSION:
23636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_FLAGS:
23646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_BASE_ADDRESS:
23656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_UNREFEXTNO:
23666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2367d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
23686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_SYMTABNO:
2369047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_symtabno_ = d->d_un.d_val;
23706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2371d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
23726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_LOCAL_GOTNO:
2373047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_local_gotno_ = d->d_un.d_val;
23746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2375d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
23766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_GOTSYM:
2377047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_gotsym_ = d->d_un.d_val;
23786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
23794eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
2380ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2381ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      case DT_BIND_NOW:
2382ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov        break;
2383ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2384ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Ignore: bionic does not support symbol versioning...
2385513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERSYM:
2386513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEF:
2387513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEFNUM:
2388e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEED:
2389e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEEDNUM:
2390513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2391d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
23926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
23938f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        if (!relocating_linker) {
23946cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov          DL_WARN("%s: unused DT entry: type %p arg %p", name,
23958f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov              reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
23968f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        }
23976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
23981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
23996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
2402047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        reinterpret_cast<void*>(base), strtab_, symtab_);
24031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Sanity checks.
24056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (relocating_linker && needed_count != 0) {
24066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
24076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
24086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2409047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (nbucket_ == 0) {
2410ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" (new hash type from the future?)", name);
24116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
24126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2413047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (strtab_ == 0) {
24146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("empty/missing DT_STRTAB in \"%s\"", name);
24156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
24166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2417047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (symtab_ == 0) {
24186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name);
24196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
24206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
242214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
24231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2424047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group, const android_dlextinfo* extinfo) {
24251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2426ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_ = local_group.front();
2427ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (local_group_root_ == nullptr) {
2428ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_group_root_ = this;
2429ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
2430ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2431e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__)
24326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (has_text_relocations) {
24336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // Make segments writable to allow text relocations to work properly. We will later call
24346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
24356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_WARN("%s has text relocations. This is wasting memory and prevents "
24366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            "security hardening. Please fix.", name);
24376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
24386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("can't unprotect loadable segments for \"%s\": %s",
24396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
24406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
24415135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich    }
24426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2443e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
24445135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich
24454eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2446047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rela_ != nullptr) {
24476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s ]", name);
2448047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    if (relocate(rela_, rela_count_, global_group, local_group)) {
24496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2450c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
24516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2452047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rela_ != nullptr) {
24536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s plt ]", name);
2454047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    if (relocate(plt_rela_, plt_rela_count_, global_group, local_group)) {
24556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
24561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
24576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24589aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else
2459047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rel_ != nullptr) {
24606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s ]", name);
2461047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    if (relocate(rel_, rel_count_, global_group, local_group)) {
24626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
24631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
24646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2465047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rel_ != nullptr) {
24666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("[ relocating %s plt ]", name);
2467047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    if (relocate(plt_rel_, plt_rel_count_, global_group, local_group)) {
24686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2469c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith    }
24706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24719aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif
2472c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
24734eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
2474889409168322920ab6cddeb93f506c983d8b5878Dmitriy Ivanov  if (!mips_relocate_got(global_group, local_group)) {
24756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
24766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2477d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif
2478d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
24796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  DEBUG("[ finished linking %s ]", name);
24801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2481e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__)
24826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (has_text_relocations) {
24836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // All relocations are done, we can protect our segments back to read-only.
24846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
24856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("can't protect segments for \"%s\": %s",
24866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
24876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
24881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
24896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2490e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif
24911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can also turn on GNU RELRO protection */
24936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
24946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
24956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           name, strerror(errno));
24966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
24976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24989ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich
24996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Handle serializing/sharing the RELRO segment */
25006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
25016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
25026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                       extinfo->relro_fd) < 0) {
25036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
25046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
25056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2506183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)    }
25076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
25086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
25096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                 extinfo->relro_fd) < 0) {
25106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
25116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             name, strerror(errno));
25126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
25136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
25146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2515183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)
25166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  notify_gdb_of_load(this);
25176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
25181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
25191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2520468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
2521c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list.
2522c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers.
2523c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc.
2524c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */
2525812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) {
25264eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR)
25270266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
2528851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (ehdr_vdso == nullptr) {
25290266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    return;
25300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
2531c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
253207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0);
2533ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
25340266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
25350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phnum = ehdr_vdso->e_phnum;
25360266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
25370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
25380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
2539ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
2540047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->prelink_image();
2541047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr);
2542c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif
2543c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
2544c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
2545c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/*
2546d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below.
2547d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
25480d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__)
25490d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64"
25500d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else
25510d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker"
25520d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif
255307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanovstatic soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0, 0);
2554d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2555d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list.
2556d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text"
2557d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to
2558d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
2559d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't
2560d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list.
2561d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
2562d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
2563d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  linker_soinfo_for_gdb.base = linker_base;
2564d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2565d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  /*
2566d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * Set the dynamic field in the link map otherwise gdb will complain with
2567d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * the following:
2568d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   warning: .dynamic section for "/system/bin/linker" is not at the
2569d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   expected address (wrong library or version mismatch?)
2570d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   */
2571d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
2572d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
2573d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
2574e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian                                 &linker_soinfo_for_gdb.dynamic, nullptr);
2575d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  insert_soinfo_into_debug_map(&linker_soinfo_for_gdb);
2576d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2577d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2578d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/*
2579468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and
2580468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs
2581468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point.
2582468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
25830266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
25841a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING
25856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  struct timeval t0, t1;
25866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t0, 0);
25871a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif
25881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
25896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Initialize environment functions, and get to the ELF aux vectors table.
25906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  linker_env_init(args);
2591be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
25926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // If this is a setuid/setgid program, close the security hole described in
25936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
25946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (get_AT_SECURE()) {
25956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    nullify_closed_stdio();
25966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
25978d3e91d4f842911366155845afb3cfbdad0b4cadNick Kralevich
25986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  debuggerd_init();
25991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Get a few environment variables.
26016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* LD_DEBUG = linker_env_get("LD_DEBUG");
26026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (LD_DEBUG != nullptr) {
26036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    g_ld_debug_verbosity = atoi(LD_DEBUG);
26046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2605be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
26066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Normally, these are cleaned by linker_env_init, but the test
26076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // doesn't cost us anything.
26086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpath_env = nullptr;
26096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpreload_env = nullptr;
26106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!get_AT_SECURE()) {
26116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ldpath_env = linker_env_get("LD_LIBRARY_PATH");
26126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ldpreload_env = linker_env_get("LD_PRELOAD");
26136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
26141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2615bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#if !defined(__LP64__)
2616bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov  if (personality(PER_LINUX32) == -1) {
2617bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov    __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
2618bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov  }
2619bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#endif
2620bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov
26216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  INFO("[ android linker & debugger ]");
26221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
262307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
26246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
26256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
26266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
26271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* bootstrap the link map, the main exe always needs to be first */
2629ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  si->set_main_executable();
26306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(si->link_map_head);
26311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = 0;
26336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_name = args.argv[0];
26346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_prev = nullptr;
26356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_next = nullptr;
26361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_map = map;
26386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
26391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  init_linker_info_for_gdb(linker_base);
26411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract information passed from the kernel.
26436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
26446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phnum = args.getauxval(AT_PHNUM);
26456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->entry = args.getauxval(AT_ENTRY);
26461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Compute the value of si->base. We can't rely on the fact that
26486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * the first entry is the PHDR because this will not be true
26496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * for certain executables (e.g. some in the NDK unit test suite)
26506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   */
26516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->base = 0;
26526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
26536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->load_bias = 0;
26546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t i = 0; i < si->phnum; ++i) {
26556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (si->phdr[i].p_type == PT_PHDR) {
26566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
26576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
26586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
26598180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner    }
26606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
26616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->dynamic = nullptr;
26621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
26636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
26646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (elf_hdr->e_type != ET_DYN) {
26656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n");
26666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
26676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
26682aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich
26696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
26706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_LIBRARY_PATH(ldpath_env);
26716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_PRELOAD(ldpreload_env);
26724fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
26736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  somain = si;
26745ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel
26756718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  if (!si->prelink_image()) {
26766718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
26776718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    exit(EXIT_FAILURE);
26786718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  }
267914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
2680d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // add somain to global group
2681d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
2682d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
26836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Load ld_preloads and dependencies.
26846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  StringLinkedList needed_library_name_list;
26856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t needed_libraries_count = 0;
26866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t ld_preloads_count = 0;
26876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  while (g_ld_preload_names[ld_preloads_count] != nullptr) {
26886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]);
26896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
26906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
269114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
26926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for_each_dt_needed(si, [&](const char* name) {
26936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    needed_library_name_list.push_back(name);
26946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
26956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  });
269614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
26976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* needed_library_names[needed_libraries_count];
269814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
26996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  memset(needed_library_names, 0, sizeof(needed_library_names));
27006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
270114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
2702cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (needed_libraries_count > 0 && !find_libraries(si, needed_library_names, needed_libraries_count, nullptr, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
27036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
27046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
2705ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else if (needed_libraries_count == 0) {
2706ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
2707ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
2708ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      exit(EXIT_FAILURE);
2709ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
2710ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    si->increment_ref_count();
27116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
27121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
27136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  add_vdso(args);
2714c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
2715047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->call_pre_init_constructors();
27169181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
2717047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  /* After the prelink_image, the si->load_bias is initialized.
27186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
27196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * We need to update this value for so exe here. So Unwind_Backtrace
27206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * for some arch like x86 could work correctly within so exe.
27216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   */
27226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = si->load_bias;
2723047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->call_constructors();
2724e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
27251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
27266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t1, nullptr);
27276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
27286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
27296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
27301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
27311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
27326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0],
27336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocAbsolute],
27346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocRelative],
27356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocCopy],
27366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocSymbol]);
27371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
27381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
27396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  {
27406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned n;
27416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned i;
27426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned count = 0;
27436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    for (n = 0; n < 4096; n++) {
27446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (bitmask[n]) {
27456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        unsigned x = bitmask[n];
2746e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__)
27476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 32; i++) {
2748e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else
27496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 8; i++) {
2750e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif
27516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          if (x & 1) {
27526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            count++;
27536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          }
27546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          x >>= 1;
27551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
27566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
27571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
27586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4);
27596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
27601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
27611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
27621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
27636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  fflush(stdout);
27641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
27651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
27666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  TRACE("[ Ready to execute '%s' @ %p ]", si->name, reinterpret_cast<void*>(si->entry));
27676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return si->entry;
27681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2769468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
2770bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only
2771bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library
2772bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself.
2773bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *
2774bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input:
2775bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    elf    -> address of ELF header, assumed to be at the start of the file.
2776bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return:
2777bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    load bias, i.e. add the value of any p_vaddr in the file to get
2778bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    the corresponding address in memory.
2779bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */
27800266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
27810266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) offset = elf->e_phoff;
2782faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  const ElfW(Phdr)* phdr_table = reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
27830266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
2784fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
27850266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
2786fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (phdr->p_type == PT_LOAD) {
27870266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
2788bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner    }
2789fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
2790fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  return 0;
2791bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner}
2792bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner
2793efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start();
2794efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
2795468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
2796468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This
2797468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and
2798468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation().
2799468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich *
2800468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own
2801468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern
2802468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault.
2803468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
28040266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) {
280542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  KernelArgumentBlock args(raw_args);
280642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
28070266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
2808efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
28090266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
2810faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
281142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
281207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo linker_so("[dynamic linker]", nullptr, 0, 0);
281342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
2814efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // If the linker is not acting as PT_INTERP entry_point is equal to
2815efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // _start. Which means that the linker is running as an executable and
2816efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // already linked by PT_INTERP.
2817efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  //
2818efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // This happens when user tries to run 'adb shell /system/bin/linker'
2819efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // see also https://code.google.com/p/android/issues/detail?id=63174
2820efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
2821efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
2822efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  }
2823efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
282442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.base = linker_addr;
282542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
282642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
2827851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  linker_so.dynamic = nullptr;
282842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phdr = phdr;
282942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phnum = elf_hdr->e_phnum;
2830ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  linker_so.set_linker_flag();
283142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
2832d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // This might not be obvious... The reasons why we pass g_empty_list
2833d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // in place of local_group here are (1) we do not really need it, because
2834d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
2835d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // itself without having to look into local_group and (2) allocators
2836d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // are not yet initialized, and therefore we cannot use linked_list.push_*
2837d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // functions at this point.
2838047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
283942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // It would be nice to print an error message, but if the linker
284042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // can't link itself, there's no guarantee that we'll be able to
2841b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // call write() (because it involves a GOT reference). We may as
2842b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // well try though...
2843b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    const char* msg = "CANNOT LINK EXECUTABLE: ";
2844b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, msg, strlen(msg));
2845b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
2846b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, "\n", 1);
2847b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    _exit(EXIT_FAILURE);
284842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
2849468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
285014241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov  __libc_init_tls(args);
285114241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov
2852efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // Initialize the linker's own global variables
2853047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  linker_so.call_constructors();
28544151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov
28550d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // Initialize static variables. Note that in order to
28560d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // get correct libdl_info we need to call constructors
28570d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // before get_libdl_info().
28580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  solist = get_libdl_info();
28590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  sonext = get_libdl_info();
28600d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
286142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // We have successfully fixed our own relocations. It's safe to run
286242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // the main part of the linker now.
28631728b2396591853345507a063ed6075dfd251706Elliott Hughes  args.abort_message_ptr = &g_abort_message;
28640266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
28655419b9474753d25dff947c7740532f86d130c0beElliott Hughes
2866d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  protect_data(PROT_READ);
2867d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
286842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // Return the address that the calling assembly stub should jump to.
286942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  return start_address;
2870468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich}
2871