linker.cpp revision 07f4f5f9edc33d22c41f51224f8be0c0a51e5b6b
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
22a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov * Copyright (C) 2008 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
2904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov#include <android/api-level.h>
304688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <dlfcn.h>
314688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <errno.h>
324688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <fcntl.h>
330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <inttypes.h>
344688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <pthread.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
384688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <sys/mman.h>
39ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#include <sys/param.h>
40bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#include <sys/personality.h>
414688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h>
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
430d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new>
44d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <string>
45d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <vector>
460d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
474688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers.
48eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h"
49eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h"
50eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h"
5114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/ScopeGuard.h"
5214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/UniquePtr.h"
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h"
55c9ce70d7838b6aae074fc3615cdf04e5c9ac612aDmitriy Ivanov#include "linker_block_allocator.h"
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h"
57be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner#include "linker_environ.h"
5818870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov#include "linker_sleb128.h"
5923363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h"
60cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#include "linker_relocs.h"
61fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker_reloc_iterators.h"
62aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin#include "ziparchive/zip_archive.h"
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here.
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past.
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo:
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   and NOEXEC
774688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes */
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
791649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov// Override macros to use C++ style casts
801649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#undef ELF_ST_TYPE
811649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
821649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov
830266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
85600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<soinfo> g_soinfo_allocator;
86600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
87ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
88d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist;
89d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext;
906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
921728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = {
934eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__)
94011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/vendor/lib64",
95011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/system/lib64",
96011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else
97124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/vendor/lib",
98124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/system/lib",
99011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif
100851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  nullptr
101124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes};
102124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
1032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymNotNeeded = 0;
1042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymGlobal = 1;
1052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
106d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_library_paths;
107d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_preload_names;
108a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
109d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<soinfo*> g_ld_preloads;
1104fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
1111728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity;
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
113851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
1140d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
116bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t {
1176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int count[kRelocMax];
118bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes};
119bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
120bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats;
121bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
122114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind kind) {
1236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ++linker_stats.count[kind];
124bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
125bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else
126114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind) {
127bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
131114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovuint32_t bitmask[4096];
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1342e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1352e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
136650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() {
1375419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return &__linker_dl_err_buf[0];
1382e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1392e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
140650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() {
141650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes  return sizeof(__linker_dl_err_buf);
142650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes}
143650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes
1446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified
1456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity.
14620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovextern "C"
14720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1491728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
15020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic r_debug _r_debug =
15120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov    {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
15220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov
1533a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0;
1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1553a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) {
1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Copy the necessary fields into the debug structure.
1576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = info->load_bias;
159aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  // link_map l_name field is not const.
160aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  map->l_name = const_cast<char*>(info->get_realpath());
1616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_ld = info->dynamic;
1626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
1636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Stick the new library at the end of the list.
1646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // gdb tends to care more about libc than it does
1656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // about leaf libraries, and ordering it this way
1666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // reduces the back-and-forth over the wire.
1676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail) {
1686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail->l_next = map;
1696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = r_debug_tail;
1706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
1716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
1726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    _r_debug.r_map = map;
1736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = 0;
1746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
1756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
179bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) {
1806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1815e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail == map) {
1836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail = map->l_prev;
1846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1855e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_prev) {
1876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev->l_next = map->l_next;
1886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_next) {
1906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next->l_prev = map->l_prev;
1916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1925e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
1935e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
194bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) {
195ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
1966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
1976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
1986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_ADD;
2036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  insert_soinfo_into_debug_map(info);
2061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2095e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2105e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
211bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) {
212ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
2136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
2146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2165e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2185e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_DELETE;
2206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2215e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  remove_soinfo_from_debug_map(info);
2235e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22818a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() {
2293a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_ADD;
2303a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2313a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_CONSISTENT;
2323a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
235d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
236d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  return g_soinfo_links_allocator.alloc();
237d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
238d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
239d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
240d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_links_allocator.free(entry);
241d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
242d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
24320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat,
24420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                            off64_t file_offset, uint32_t rtld_flags) {
245aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (strlen(name) >= PATH_MAX) {
246ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn    DL_ERR("library name \"%s\" too long", name);
247851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
248ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  }
249ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
25007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
251d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
252ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext->next = si;
253ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext = si;
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
255ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("name %s: allocated soinfo @ %p", name, si);
256ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  return si;
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
259faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) {
2606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
2616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2634688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
2646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si->base != 0 && si->size != 0) {
2656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    munmap(reinterpret_cast<void*>(si->base), si->size);
2666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
267d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  soinfo *prev = nullptr, *trav;
2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
270b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (trav = solist; trav != nullptr; trav = trav->next) {
2736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (trav == si) {
2746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    prev = trav;
2776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
278ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (trav == nullptr) {
2806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // si was not in solist
281b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
2826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // clear links to/from si
2866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->remove_all_links();
287d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // prev will never be null, because the first entry in solist is
2896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // always the static libdl_info.
2906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  prev->next = si->next;
2916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == sonext) {
2926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    sonext = prev;
2936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
294d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
2956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  g_soinfo_allocator.free(si);
2961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
298cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_path(const char* path, const char* delimiters,
299d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov                       std::vector<std::string>* paths) {
300851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (path == nullptr) {
301cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    return;
302cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
303cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
304d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  paths->clear();
305cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
306d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (const char *p = path; ; ++p) {
307d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    size_t len = strcspn(p, delimiters);
308d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    // skip empty tokens
309d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (len == 0) {
310d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      continue;
311cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    }
312cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
313d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    paths->push_back(std::string(p, len));
314d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    p += len;
315d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
316d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (*p == '\0') {
317d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      break;
318d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
319cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
320cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
321cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
322cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_LIBRARY_PATH(const char* path) {
323d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  parse_path(path, ":", &g_ld_library_paths);
324cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
325cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
326cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_PRELOAD(const char* path) {
327cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // We have historically supported ':' as well as ' ' in LD_PRELOAD.
328d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  parse_path(path, " :", &g_ld_preload_names);
329cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
330cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
331aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic bool realpath_fd(int fd, std::string* realpath) {
332aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
333aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
334aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
335ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov    PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
336aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return false;
337aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
338aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
339aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  *realpath = std::string(&buf[0]);
340aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return true;
341aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
342aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
3434eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
3444688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// For a given PC, find the .so that it belongs to.
3466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Returns the base address of the .ARM.exidx section
3476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// for that .so, and the number of 8-byte entries
3486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// in that section (via *pcount).
3496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Intended to be called by libc's __gnu_Unwind_Find_exidx().
3516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is exposed via dlfcn.cpp and libdl.so.
353faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
3541649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov  uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != 0; si = si->next) {
3576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if ((addr >= si->base) && (addr < (si->base + si->size))) {
3586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *pcount = si->ARM_exidx_count;
3591649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  *pcount = 0;
3636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return nullptr;
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3654688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
36624053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif
3674688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Here, we only have to provide a callback to iterate across all the
3696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// loaded libraries. gcc_eh does the rest.
370faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesint dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
3716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int rv = 0;
3726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
3736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_phdr_info dl_info;
3746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_addr = si->link_map_head.l_addr;
3756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_name = si->link_map_head.l_name;
3766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phdr = si->phdr;
3776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phnum = si->phnum;
3786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    rv = cb(&dl_info, sizeof(dl_phdr_info), data);
3796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (rv != 0) {
3806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return rv;
3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3854688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst ElfW(Versym)* soinfo::get_versym(size_t n) const {
3872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2) && versym_ != nullptr) {
3882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return versym_ + n;
3892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
3902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return nullptr;
3922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
3932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3942a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verneed_ptr() const {
3952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
3962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verneed_ptr_;
3972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
3982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
4002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verneed_cnt() const {
4032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
4042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verneed_cnt_;
4052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
4082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4102a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verdef_ptr() const {
4112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
4122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verdef_ptr_;
4132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
4162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verdef_cnt() const {
4192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
4202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verdef_cnt_;
4212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
4242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovtemplate<typename F>
4272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic bool for_each_verdef(const soinfo* si, F functor) {
4282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!si->has_min_version(2)) {
4292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
4302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  uintptr_t verdef_ptr = si->get_verdef_ptr();
4332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (verdef_ptr == 0) {
4342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
4352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  size_t offset = 0;
4382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  size_t verdef_cnt = si->get_verdef_cnt();
4402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  for (size_t i = 0; i<verdef_cnt; ++i) {
4412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
4422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    size_t verdaux_offset = offset + verdef->vd_aux;
4432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    offset += verdef->vd_next;
4442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verdef->vd_version != 1) {
4463d7bea1fa00342f2a18331ea33a4b6e3332b3b02Dmitriy Ivanov      DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
447b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          i, verdef->vd_version, si->get_realpath());
4482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
4492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
4522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      // "this is the version of the file itself.  It must not be used for
4532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      //  matching a symbol. It can be used to match references."
4542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      //
4552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      // http://www.akkadia.org/drepper/symbol-versioning
4562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      continue;
4572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verdef->vd_cnt == 0) {
4602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
4612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
4622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
4652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (functor(i, verdef, verdaux) == true) {
4672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      break;
4682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
4722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const {
4752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (vi == nullptr) {
4762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    *versym = kVersymNotNeeded;
4772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
4782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *versym = kVersymGlobal;
4812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return for_each_verdef(this,
4832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
4842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      if (verdef->vd_hash == vi->elf_hash &&
4852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov          strcmp(vi->name, get_string(verdaux->vda_name)) == 0) {
4862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        *versym = verdef->vd_ndx;
4872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        return true;
4882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
4892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
4912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  );
4932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_symbol_by_name(SymbolName& symbol_name,
4962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                 const version_info* vi,
4972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                 const ElfW(Sym)** symbol) const {
4982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  uint32_t symbol_index;
4992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  bool success =
5002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      is_gnu_hash() ?
5012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      gnu_lookup(symbol_name, vi, &symbol_index) :
5022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      elf_lookup(symbol_name, vi, &symbol_index);
5032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (success) {
5052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
5062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
5072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return success;
509ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
510ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
511ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
512ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
513ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      ELF_ST_BIND(s->st_info) == STB_WEAK) {
514ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    return s->st_shndx != SHN_UNDEF;
515ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
516ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
517b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
518ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
519ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
520ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return false;
521ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
522ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
5232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymHiddenBit = 0x8000;
5242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool is_versym_hidden(const ElfW(Versym)* versym) {
5262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // the symbol is hidden if bit 15 of versym is set.
5272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return versym != nullptr && (*versym & kVersymHiddenBit) != 0;
5282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
5292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool check_symbol_version(const ElfW(Versym) verneed,
5312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                        const ElfW(Versym)* verdef) {
5322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return verneed == kVersymNotNeeded ||
5332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      verdef == nullptr ||
5342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      verneed == (*verdef & ~kVersymHiddenBit);
5352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
5362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::gnu_lookup(SymbolName& symbol_name,
5382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        const version_info* vi,
5392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        uint32_t* symbol_index) const {
540ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t hash = symbol_name.gnu_hash();
541047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  uint32_t h2 = hash >> gnu_shift2_;
5421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
543ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
544047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
545047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
5461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *symbol_index = 0;
5482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5493597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
550b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
5513597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
552ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  // test against bloom filter
553ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
5543597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
555b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
5563597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
5572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
558ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
559ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
560ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  // bloom test says "probably yes"...
5613597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
562ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
563ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (n == 0) {
5643597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
565b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
5663597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
5672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
5682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
5692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // lookup versym for the version definition in this library
5712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // note the difference between "version is not requested" (vi == nullptr)
5722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // and "version not found". In the first case verneed is kVersymNotNeeded
5732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // which implies that the default version can be accepted; the second case results in
5742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
5752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // for this library and consider only *global* ones.
5762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ElfW(Versym) verneed = 0;
5772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!find_verdef_version_index(vi, &verneed)) {
5782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return false;
579ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
580ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
581ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  do {
582047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* s = symtab_ + n;
5832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Versym)* verdef = get_versym(n);
5842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    // skip hidden versions when verneed == kVersymNotNeeded (0)
5852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
5862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        continue;
5872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
5883597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
5892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        check_symbol_version(verneed, verdef) &&
590ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
591ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        is_symbol_global_and_defined(this, s)) {
5923597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
593b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
5943597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov          static_cast<size_t>(s->st_size));
5952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      *symbol_index = n;
5962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return true;
597ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
5983597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  } while ((gnu_chain_[n++] & 1) == 0);
5993597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
6003597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
601b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
6021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
604ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
605ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
6062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::elf_lookup(SymbolName& symbol_name,
6072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        const version_info* vi,
6082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        uint32_t* symbol_index) const {
609ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t hash = symbol_name.elf_hash();
610ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
611ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
612b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             symbol_name.get_name(), get_realpath(),
613aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov             reinterpret_cast<void*>(base), hash, hash % nbucket_);
614ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
6152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ElfW(Versym) verneed = 0;
6162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!find_verdef_version_index(vi, &verneed)) {
6172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return false;
6182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
6192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
620047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
621047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* s = symtab_ + n;
6222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Versym)* verdef = get_versym(n);
6232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
6242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    // skip hidden versions when verneed == 0
6252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
6262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        continue;
6272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
6282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
6292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (check_symbol_version(verneed, verdef) &&
6302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
63120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        is_symbol_global_and_defined(this, s)) {
632ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
633b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov                 symbol_name.get_name(), get_realpath(),
634aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov                 reinterpret_cast<void*>(s->st_value),
635aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov                 static_cast<size_t>(s->st_size));
6362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      *symbol_index = n;
6372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return true;
6381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6390266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
6401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
641aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
642b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             symbol_name.get_name(), get_realpath(),
643aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov             reinterpret_cast<void*>(base), hash, hash % nbucket_);
644aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
6452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *symbol_index = 0;
6462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
6471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
649aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovsoinfo::soinfo(const char* realpath, const struct stat* file_stat,
65020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov               off64_t file_offset, int rtld_flags) {
6510d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  memset(this, 0, sizeof(*this));
6520d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
653aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (realpath != nullptr) {
654aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    realpath_ = realpath;
655aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
656aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
657ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ = FLAG_NEW_SOINFO;
658047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  version_ = SOINFO_VERSION;
6590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
660851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (file_stat != nullptr) {
661047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->st_dev_ = file_stat->st_dev;
662047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->st_ino_ = file_stat->st_ino;
663047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->file_offset_ = file_offset;
6640d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  }
665e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
666047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  this->rtld_flags_ = rtld_flags;
6670d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov}
6680d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
6696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
670ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::elf_hash() {
671ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (!has_elf_hash_) {
672aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
673ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    uint32_t h = 0, g;
674ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
675ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    while (*name) {
676ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h = (h << 4) + *name++;
677ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      g = h & 0xf0000000;
678ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h ^= g;
679ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h ^= g >> 24;
680ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
681ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
682ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    elf_hash_ = h;
683ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    has_elf_hash_ = true;
6846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
685ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
686ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return elf_hash_;
687ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
688ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
689ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::gnu_hash() {
690ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (!has_gnu_hash_) {
691ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    uint32_t h = 5381;
692aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
693ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    while (*name != 0) {
694ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
695ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
696ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
697ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    gnu_hash_ =  h;
698ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    has_gnu_hash_ = true;
699ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
700ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
701ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return gnu_hash_;
7021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
7052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                      soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
7062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                      const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
707ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  SymbolName symbol_name(name);
7082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  const ElfW(Sym)* s = nullptr;
7096ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
71096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  /* "This element's presence in a shared object library alters the dynamic linker's
71196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * symbol resolution algorithm for references within the library. Instead of starting
71296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * a symbol search with the executable file, the dynamic linker starts from the shared
71396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * object itself. If the shared object fails to supply the referenced symbol, the
71496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * dynamic linker then searches the executable file and other shared objects as usual."
71596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   *
71696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
71796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   *
71896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * Note that this is unlikely since static linker avoids generating
71996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * relocations for -Bsymbolic linked dynamic executables.
72096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   */
721d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (si_from->has_DT_SYMBOLIC) {
722b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
7232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
7242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
7252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
7262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
7278f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    if (s != nullptr) {
728d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      *si_found_in = si_from;
72996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov    }
73096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  }
73196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov
732d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // 1. Look for it in global_group
733d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (s == nullptr) {
7342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    bool error = false;
735d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    global_group.visit([&](soinfo* global_si) {
736aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      DEBUG("%s: looking up %s in %s (from global group)",
737b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          si_from->get_realpath(), name, global_si->get_realpath());
7382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
7392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        error = true;
7402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        return false;
7412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
7422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
74396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov      if (s != nullptr) {
744d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        *si_found_in = global_si;
745d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        return false;
74696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov      }
747c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
748d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      return true;
749d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    });
7502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
7512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (error) {
7522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
7532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
75496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  }
755c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
756d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // 2. Look for it in the local group
757cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (s == nullptr) {
7582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    bool error = false;
759cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    local_group.visit([&](soinfo* local_si) {
760d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
761e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov        // we already did this - skip
762e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov        return true;
763e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov      }
764e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov
765aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      DEBUG("%s: looking up %s in %s (from local group)",
766b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          si_from->get_realpath(), name, local_si->get_realpath());
7672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
7682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        error = true;
7692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        return false;
7702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
7712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
772cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      if (s != nullptr) {
773d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        *si_found_in = local_si;
774cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov        return false;
775cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      }
7766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
777cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return true;
778cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    });
7792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
7802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (error) {
7812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
7822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
783cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
784cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
7856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (s != nullptr) {
7866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
7876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov               "found in %s, base = %p, load bias = %p",
788b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov               si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
789b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov               (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
790d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov               reinterpret_cast<void*>((*si_found_in)->load_bias));
7916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
7926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
7932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *symbol = s;
7942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
7956ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
7966ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
797279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovclass ProtectedDataGuard {
798279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov public:
799279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ProtectedDataGuard() {
800279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    if (ref_count_++ == 0) {
801279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov      protect_data(PROT_READ | PROT_WRITE);
802279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    }
803279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
804279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
805279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ~ProtectedDataGuard() {
806279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    if (ref_count_ == 0) { // overflow
807279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov      __libc_fatal("Too many nested calls to dlopen()");
808279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    }
809279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
810279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    if (--ref_count_ == 0) {
811279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov      protect_data(PROT_READ);
812279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    }
813279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
814279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov private:
815279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  void protect_data(int protection) {
816279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    g_soinfo_allocator.protect_all(protection);
817279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    g_soinfo_links_allocator.protect_all(protection);
818279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
819279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
820279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  static size_t ref_count_;
821279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov};
822279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
823279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovsize_t ProtectedDataGuard::ref_count_ = 0;
824279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
8250cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator.
8260cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
8270cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator {
8280cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
8290cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void* alloc() {
8300cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return allocator_.alloc();
8310cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8320cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8330cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(void* ptr) {
8340cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    allocator_.free(ptr);
8350cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8364bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov
8370cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private:
8380cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static LinkerBlockAllocator allocator_;
8390cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
8400cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8410cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
8420cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
8430cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8440cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T>
8450cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator {
8460cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
8470cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static T* alloc() {
8480cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
8490cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8500cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8510cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(T* ptr) {
8520cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    SizeBasedAllocator<sizeof(T)>::free(ptr);
8530cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8540cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
8550cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
85614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask {
85714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public:
85814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct deleter_t {
85914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    void operator()(LoadTask* t) {
86014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      TypeBasedAllocator<LoadTask>::free(t);
86114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
86214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  };
863a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
86414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef UniquePtr<LoadTask, deleter_t> unique_ptr;
865d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom
86614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static deleter_t deleter;
86714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
86814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static LoadTask* create(const char* name, soinfo* needed_by) {
86914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
87014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return new (ptr) LoadTask(name, needed_by);
871aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
872a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
87314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* get_name() const {
87414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return name_;
875a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
87614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
87714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* get_needed_by() const {
87814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return needed_by_;
87914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
88014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private:
88114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTask(const char* name, soinfo* needed_by)
88214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    : name_(name), needed_by_(needed_by) {}
88314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
88414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* name_;
88514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* needed_by_;
88614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
88714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
888aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov};
889aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
890e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng JianLoadTask::deleter_t LoadTask::deleter;
891e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian
89214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T>
89314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
89414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
89514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList;
89614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList;
89714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<LoadTask> LoadTaskList;
89814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
89914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
900cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// This function walks down the tree of soinfo dependencies
901cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// in breadth-first order and
902cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//   * calls action(soinfo* si) for each node, and
903cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//   * terminates walk if action returns false.
904cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//
905cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// walk_dependencies_tree returns false if walk was terminated
906cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// by the action and true otherwise.
907cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovtemplate<typename F>
908cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovstatic bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
9090cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visit_list;
9100cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visited;
9110cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
912cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  for (size_t i = 0; i < root_soinfos_size; ++i) {
913cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    visit_list.push_back(root_soinfos[i]);
914cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
915cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
916cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  soinfo* si;
917cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  while ((si = visit_list.pop_front()) != nullptr) {
918cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (visited.contains(si)) {
919042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov      continue;
920042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov    }
921042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov
922cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (!action(si)) {
923cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return false;
924aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    }
925aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
926cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    visited.push_back(si);
927cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
928cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    si->get_children().for_each([&](soinfo* child) {
929aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov      visit_list.push_back(child);
930aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    });
931aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
932aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
933cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return true;
934cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
935cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
936cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
9374bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanovstatic const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
9384bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov                                            soinfo** found, SymbolName& symbol_name) {
9392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  const ElfW(Sym)* result = nullptr;
9404bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  bool skip_lookup = skip_until != nullptr;
9414bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov
9424bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
9434bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov    if (skip_lookup) {
9444bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov      skip_lookup = current_soinfo != skip_until;
9454bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov      return true;
9464bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov    }
947cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
9482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
9492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      result = nullptr;
9502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
9512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
9522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
953cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (result != nullptr) {
954cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      *found = current_soinfo;
955cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return false;
956cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    }
957cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
958cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
959cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
960cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
961cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return result;
9621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9644bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov// This is used by dlsym(3).  It performs symbol lookup only within the
9654bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov// specified soinfo object and its dependencies in breadth first order.
9664bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanovconst ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
967c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // According to man dlopen(3) and posix docs in the case when si is handle
968c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // of the main executable we need to search not only in the executable and its
969c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // dependencies but also in all libraries loaded with RTLD_GLOBAL.
970c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  //
971c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
972c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // libraries and they are loaded in breath-first (correct) order we can just execute
973c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
974c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  if (si == somain) {
975c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov    return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT);
976c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  }
977c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov
9784bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  SymbolName symbol_name(name);
9794bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  return dlsym_handle_lookup(si, nullptr, found, symbol_name);
9804bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov}
9814bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov
982d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the
983d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   start value is null (for RTLD_DEFAULT), the search starts at the
984d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   beginning of the global solist. Otherwise the search starts at the
985d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   specified soinfo (for RTLD_NEXT).
9866ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
9872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst ElfW(Sym)* dlsym_linear_lookup(const char* name,
9882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                     soinfo** found,
9892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                     soinfo* caller,
9902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                     void* handle) {
991ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  SymbolName symbol_name(name);
9921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
99376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  soinfo* start = solist;
99476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
99576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  if (handle == RTLD_NEXT) {
99615309fde91b3989a1af139db422acf68e16a9258Dmitriy Ivanov    if (caller == nullptr) {
99776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov      return nullptr;
99876ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov    } else {
99976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov      start = caller->next;
100076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov    }
1001cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
10021698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer
10032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  const ElfW(Sym)* s = nullptr;
100476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  for (soinfo* si = start; si != nullptr; si = si->next) {
100504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
100604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    // if the library is opened by application with target api level <= 22
100704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    // See http://b/21565766
100804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
1009e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov      continue;
1010e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    }
1011e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
10122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
10132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return nullptr;
10142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
10152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1016851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    if (s != nullptr) {
1017cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      *found = si;
1018cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      break;
10191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1020cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
10211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10224bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  // If not found - use dlsym_handle_lookup for caller's
10234bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  // local_group unless it is part of the global group in which
102476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  // case we already did it.
102576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  if (s == nullptr && caller != nullptr &&
102676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov      (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
10274bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov    return dlsym_handle_lookup(caller->get_local_group_root(),
10284bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov        (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name);
102976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  }
103076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
1031851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (s != nullptr) {
1032c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
1033c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes               name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
1034cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
10351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1036cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  return s;
10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1039fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) {
10400266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
1041851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
1042fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (address >= si->base && address - si->base < si->size) {
1043fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return si;
1044e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
1045fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
1046851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
1047e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
1048e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
1049ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
1050ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
1051ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1052ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1053ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
1054ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return sym->st_shndx != SHN_UNDEF &&
1055ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      soaddr >= sym->st_value &&
1056ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      soaddr < sym->st_value + sym->st_size;
1057ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1058ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1059ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
10608e5538193915885ea859ac90a72b46ab04440ceaChris Dearman  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
1061ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
10623597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  for (size_t i = 0; i < gnu_nbucket_; ++i) {
10633597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    uint32_t n = gnu_bucket_[i];
1064ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1065ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    if (n == 0) {
1066ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      continue;
1067ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
1068ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1069ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    do {
1070047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      ElfW(Sym)* sym = symtab_ + n;
1071ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      if (symbol_matches_soaddr(sym, soaddr)) {
1072ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        return sym;
1073ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      }
10743597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    } while ((gnu_chain_[n++] & 1) == 0);
1075ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
1076ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1077ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return nullptr;
1078ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1079ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1080ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
10818e5538193915885ea859ac90a72b46ab04440ceaChris Dearman  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
1082fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
1083fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // Search the library's symbol table for any defined symbol which
1084fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // contains this address.
1085047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (size_t i = 0; i < nchain_; ++i) {
1086047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* sym = symtab_ + i;
1087ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    if (symbol_matches_soaddr(sym, soaddr)) {
1088fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return sym;
1089e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
1090fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
1091e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
1092851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
1093e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
1094e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
1095aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwinstatic int open_library_in_zipfile(const char* const path,
1096aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin                                   off64_t* file_offset) {
1097aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  TRACE("Trying zip file open from path '%s'", path);
1098aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1099aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // Treat an '!' character inside a path as the separator between the name
1100aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // of the zip file on disk and the subdirectory to search within it.
1101aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // For example, if path is "foo.zip!bar/bas/x.so", then we search for
1102aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // "bar/bas/x.so" within "foo.zip".
1103aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  const char* separator = strchr(path, '!');
1104aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (separator == nullptr) {
1105aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1106aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1107aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1108aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  char buf[512];
1109aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
1110aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    PRINT("Warning: ignoring very long library path: %s", path);
1111aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1112aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1113aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1114aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  buf[separator - path] = '\0';
1115aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1116aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  const char* zip_path = buf;
1117aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  const char* file_path = &buf[separator - path + 1];
1118aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
1119aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (fd == -1) {
1120aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1121aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1122aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1123aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  ZipArchiveHandle handle;
1124aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (OpenArchiveFd(fd, "", &handle, false) != 0) {
1125aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    // invalid zip-file (?)
1126aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    close(fd);
1127aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1128aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1129aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1130aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  auto archive_guard = make_scope_guard([&]() {
1131aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    CloseArchive(handle);
1132aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  });
1133aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1134aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  ZipEntry entry;
1135aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1136aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (FindEntry(handle, ZipEntryName(file_path), &entry) != 0) {
1137aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    // Entry was not found.
1138aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    close(fd);
1139aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1140aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1141aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1142aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // Check if it is properly stored
1143aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
1144aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    close(fd);
1145aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1146aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1147aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1148aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  *file_offset = entry.offset;
1149aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  return fd;
1150aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin}
1151aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1152d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
1153d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
1154d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  if (n < 0 || n >= static_cast<int>(buf_size)) {
1155d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    PRINT("Warning: ignoring very long library path: %s/%s", path, name);
1156d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    return false;
1157d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  }
1158d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1159d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  return true;
1160d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov}
1161aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1162d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic int open_library_on_default_path(const char* name, off64_t* file_offset) {
1163d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (size_t i = 0; kDefaultLdPaths[i] != nullptr; ++i) {
1164d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    char buf[512];
1165aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    if (!format_path(buf, sizeof(buf), kDefaultLdPaths[i], name)) {
1166d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      continue;
1167d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
1168d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1169d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1170d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (fd != -1) {
1171d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      *file_offset = 0;
1172d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      return fd;
11731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1174d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  }
1175aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1176d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  return -1;
1177d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov}
1178aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1179d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic int open_library_on_ld_library_path(const char* name, off64_t* file_offset) {
1180d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (const auto& path_str : g_ld_library_paths) {
1181d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    char buf[512];
1182d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    const char* const path = path_str.c_str();
1183d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (!format_path(buf, sizeof(buf), path, name)) {
1184d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      continue;
1185d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
1186d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1187d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    int fd = -1;
1188d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (strchr(buf, '!') != nullptr) {
1189aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      fd = open_library_in_zipfile(buf, file_offset);
1190aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    }
1191aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1192aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    if (fd == -1) {
1193aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1194aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      if (fd != -1) {
1195aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin        *file_offset = 0;
1196aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      }
1197124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    }
1198d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1199d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (fd != -1) {
1200d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      return fd;
1201d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
1202124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
1203aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1204d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  return -1;
12051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1207aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwinstatic int open_library(const char* name, off64_t* file_offset) {
1208ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ opening %s ]", name);
12091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1210124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // If the name contains a slash, we should attempt to open it directly and not search the paths.
1211851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (strchr(name, '/') != nullptr) {
1212aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    if (strchr(name, '!') != nullptr) {
1213aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      int fd = open_library_in_zipfile(name, file_offset);
1214aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      if (fd != -1) {
1215aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin        return fd;
1216aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      }
1217aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    }
1218aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
12196971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
12206971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    if (fd != -1) {
1221aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      *file_offset = 0;
12226971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    }
1223e44fffd7f9b93b9ec9836cfc7acedf7e21107f8fDmitriy Ivanov    return fd;
1224124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
12251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1226124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
1227d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  int fd = open_library_on_ld_library_path(name, file_offset);
1228124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  if (fd == -1) {
1229d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    fd = open_library_on_default_path(name, file_offset);
1230124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
1231124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  return fd;
12321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12344a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanovstatic const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
12354a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov#if !defined(__LP64__)
12364a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov  // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
123704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (get_application_target_sdk_version() <= 22) {
12384a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    const char* bname = basename(dt_needed);
12394a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    if (bname != dt_needed) {
12404a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov      DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
12414a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    }
12424a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov
12434a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    return bname;
12444a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov  }
12454a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov#endif
12464a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov  return dt_needed;
12474a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov}
12484a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov
124914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F>
125014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) {
125114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
125214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (d->d_tag == DT_NEEDED) {
12534a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov      action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
1254d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    }
125514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
125614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
1257d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
12582a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Lowstatic soinfo* load_library(int fd, off64_t file_offset,
12592a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low                            LoadTaskList& load_tasks,
1260aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin                            const char* name, int rtld_flags,
1261aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin                            const android_dlextinfo* extinfo) {
126207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if ((file_offset % PAGE_SIZE) != 0) {
1263a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov    DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
126407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    return nullptr;
126507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  }
126616f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  if (file_offset < 0) {
126716f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
126816f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    return nullptr;
126916f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  }
127007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
127114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct stat file_stat;
127214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
1273a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov    DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
127414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
127514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
127616f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  if (file_offset >= file_stat.st_size) {
127720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
127820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        name, file_offset, file_stat.st_size);
127916f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    return nullptr;
128016f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  }
1281d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
128214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Check for symlink and other situations where
12839b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov  // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
12849b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov  if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
12859b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov    for (soinfo* si = solist; si != nullptr; si = si->next) {
12869b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov      if (si->get_st_dev() != 0 &&
12879b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_st_ino() != 0 &&
12889b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_st_dev() == file_stat.st_dev &&
12899b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_st_ino() == file_stat.st_ino &&
12909b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_file_offset() == file_offset) {
12919b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov        TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1292aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov            "will return existing soinfo", name, si->get_realpath());
12939b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov        return si;
12949b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov      }
1295498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov    }
129614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1297d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1298e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if ((rtld_flags & RTLD_NOLOAD) != 0) {
1299a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov    DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
130014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
130114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1302a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
1303aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  std::string realpath = name;
1304aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (!realpath_fd(fd, &realpath)) {
1305ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov    PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
1306aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    realpath = name;
1307aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
1308aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
130914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Read the ELF header and load the segments.
1310aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ElfReader elf_reader(realpath.c_str(), fd, file_offset);
131114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!elf_reader.Load(extinfo)) {
131214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
131314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1314d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1315aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
131614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (si == nullptr) {
131714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
131814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
131914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->base = elf_reader.load_start();
132014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->size = elf_reader.load_size();
132114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->load_bias = elf_reader.load_bias();
132214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phnum = elf_reader.phdr_count();
132314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phdr = elf_reader.loaded_phdr();
132414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1325047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (!si->prelink_image()) {
132614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo_free(si);
132714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
132814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1329a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
133014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for_each_dt_needed(si, [&] (const char* name) {
133114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, si));
133214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
133314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
133414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
13351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13372a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Lowstatic soinfo* load_library(LoadTaskList& load_tasks,
13382a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low                            const char* name, int rtld_flags,
13392a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low                            const android_dlextinfo* extinfo) {
13402a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
13412a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    off64_t file_offset = 0;
13422a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
13432a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low      file_offset = extinfo->library_fd_offset;
13442a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    }
13452a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo);
13462a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  }
13472a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low
13482a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  // Open the file.
13492a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  off64_t file_offset;
13502a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  int fd = open_library(name, &file_offset);
13512a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  if (fd == -1) {
13522a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    DL_ERR("library \"%s\" not found", name);
13532a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    return nullptr;
13542a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  }
13552a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
13562a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  close(fd);
13572a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  return result;
13582a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low}
13592a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low
1360618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanovstatic soinfo *find_loaded_library_by_soname(const char* name) {
1361618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // Ignore filename with path.
1362618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  if (strchr(name, '/') != nullptr) {
1363618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    return nullptr;
1364618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  }
1365618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
1366851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
1367618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    const char* soname = si->get_soname();
1368618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    if (soname != nullptr && (strcmp(name, soname) == 0)) {
1369489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov      return si;
137012c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel    }
1371489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  }
1372851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
137312c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel}
137412c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel
137520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
137620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                                     int rtld_flags, const android_dlextinfo* extinfo) {
1377618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  soinfo* si = find_loaded_library_by_soname(name);
1378b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
1379b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // Library might still be loaded, the accurate detection
138014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // of this fact is done by load_library.
1381851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (si == nullptr) {
1382618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    TRACE("[ '%s' has not been found by soname.  Trying harder...]", name);
1383e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    si = load_library(load_tasks, name, rtld_flags, extinfo);
1384b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  }
1385b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
138614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
138714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
138814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
138914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si);
139014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1391d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// TODO: this is slightly unusual way to construct
1392d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// the global group for relocation. Not every RTLD_GLOBAL
1393d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// library is included in this group for backwards-compatibility
1394d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// reasons.
1395d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov//
1396d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// This group consists of the main executable, LD_PRELOADs
1397d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// and libraries with the DF_1_GLOBAL flag set.
1398d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovstatic soinfo::soinfo_list_t make_global_group() {
1399d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  soinfo::soinfo_list_t global_group;
1400d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  for (soinfo* si = somain; si != nullptr; si = si->next) {
1401d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1402d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      global_group.push_back(si);
1403d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
1404d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
1405d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1406d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return global_group;
1407d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
1408d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1409d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic bool find_libraries(soinfo* start_with, const char* const library_names[],
1410d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      size_t library_names_count, soinfo* soinfos[], std::vector<soinfo*>* ld_preloads,
1411d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) {
141214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 0: prepare.
141314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTaskList load_tasks;
1414cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  for (size_t i = 0; i < library_names_count; ++i) {
141514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    const char* name = library_names[i];
1416cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, start_with));
1417cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
1418cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1419d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // Construct global_group.
1420d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  soinfo::soinfo_list_t global_group = make_global_group();
1421d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1422cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // If soinfos array is null allocate one on stack.
1423cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // The array is needed in case of failure; for example
1424cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // when library_names[] = {libone.so, libtwo.so} and libone.so
1425cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // is loaded correctly but libtwo.so failed for some reason.
1426cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // In this case libone.so should be unloaded on return.
1427cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // See also implementation of failure_guard below.
1428cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1429cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (soinfos == nullptr) {
1430cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1431cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1432cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    memset(soinfos, 0, soinfos_size);
143314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
143414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1435cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // list of libraries to link - see step 2.
1436cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  size_t soinfos_count = 0;
143714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1438d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto failure_guard = make_scope_guard([&]() {
143914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // Housekeeping
144014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.for_each([] (LoadTask* t) {
144114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      LoadTask::deleter(t);
144214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    });
144314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1444cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    for (size_t i = 0; i<soinfos_count; ++i) {
144514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      soinfo_unload(soinfos[i]);
144614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
144714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
144814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
144914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
145020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov  for (LoadTask::unique_ptr task(load_tasks.pop_front());
145120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      task.get() != nullptr; task.reset(load_tasks.pop_front())) {
1452e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
145314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (si == nullptr) {
145414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      return false;
145514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
145614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
145714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* needed_by = task->get_needed_by();
145814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
145914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (needed_by != nullptr) {
146014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      needed_by->add_child(si);
146114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
146214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1463ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (si->is_linked()) {
1464ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->increment_ref_count();
1465ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1466ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1467cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    // When ld_preloads is not null, the first
1468cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    // ld_preloads_count libs are in fact ld_preloads.
1469cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
1470d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // Add LD_PRELOADed libraries to the global group for future runs.
1471d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // There is no need to explicitly add them to the global group
1472d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // for this run because they are going to appear in the local
1473d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // group in the correct order.
1474d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1475d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      ld_preloads->push_back(si);
147614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
147714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1478cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (soinfos_count < library_names_count) {
1479cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      soinfos[soinfos_count++] = si;
148014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
148114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
148214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
148314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 2: link libraries.
1484cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  soinfo::soinfo_list_t local_group;
1485cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  walk_dependencies_tree(
1486cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      start_with == nullptr ? soinfos : &start_with,
1487cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      start_with == nullptr ? soinfos_count : 1,
1488cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      [&] (soinfo* si) {
1489cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    local_group.push_back(si);
1490cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
1491cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
1492cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1493ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // We need to increment ref_count in case
1494ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // the root of the local group was not linked.
1495ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  bool was_local_group_root_linked = local_group.front()->is_linked();
1496ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1497cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  bool linked = local_group.visit([&](soinfo* si) {
1498ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (!si->is_linked()) {
1499047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      if (!si->link_image(global_group, local_group, extinfo)) {
150014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        return false;
150114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      }
1502ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->set_linked();
150314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
1504cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1505cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
1506cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
1507cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1508cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (linked) {
1509cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    failure_guard.disable();
1510a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
151114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1512ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!was_local_group_root_linked) {
1513ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_group.front()->increment_ref_count();
1514ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
1515ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1516cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return linked;
151714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
151814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1519e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
152014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* si;
152114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1522ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (name == nullptr) {
1523ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    si = somain;
1524ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
152514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
152614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
152714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1528d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
1529d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
1530d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1531ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovstatic void soinfo_unload(soinfo* root) {
1532ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // Note that the library can be loaded but not linked;
1533ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // in which case there is no root but we still need
1534ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // to walk the tree and unload soinfos involved.
1535ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
1536ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // This happens on unsuccessful dlopen, when one of
1537ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // the DT_NEEDED libraries could not be linked/found.
1538ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (root->is_linked()) {
1539ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    root = root->get_local_group_root();
15401b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  }
15411b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
1542ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!root->can_unload()) {
1543b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath());
1544ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    return;
1545ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
1546d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1547ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  size_t ref_count = root->is_linked() ? root->decrement_ref_count() : 0;
1548ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1549ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (ref_count == 0) {
1550ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t local_unload_list;
1551ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t external_unload_list;
1552ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t depth_first_list;
1553ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    depth_first_list.push_back(root);
1554ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo* si = nullptr;
1555ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1556ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = depth_first_list.pop_front()) != nullptr) {
15575ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov      if (local_unload_list.contains(si)) {
15585ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov        continue;
15595ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov      }
15605ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov
1561ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      local_unload_list.push_back(si);
15625ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov
1563ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      if (si->has_min_version(0)) {
1564ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        soinfo* child = nullptr;
1565ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        while ((child = si->get_children().pop_front()) != nullptr) {
1566b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1567b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov              child->get_realpath(), child);
1568b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov
1569ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          if (local_unload_list.contains(child)) {
1570ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            continue;
15715ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov          } else if (child->is_linked() && child->get_local_group_root() != root) {
1572ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            external_unload_list.push_back(child);
1573ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else {
1574ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            depth_first_list.push_front(child);
1575ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          }
1576d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov        }
1577ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      } else {
157869a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if !defined(__work_around_b_19059885__)
1579b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
15805ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#else
1581b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1582ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        for_each_dt_needed(si, [&] (const char* library_name) {
1583aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1584b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov              si->get_realpath(), library_name);
1585aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
1586ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
1587ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          if (needed != nullptr) {
1588ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // Not found: for example if symlink was deleted between dlopen and dlclose
1589ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // Since we cannot really handle errors at this point - print and continue.
1590aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov            PRINT("warning: couldn't find %s needed by %s on unload.",
1591b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov                library_name, si->get_realpath());
1592ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            return;
1593ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else if (local_unload_list.contains(needed)) {
1594ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // already visited
1595ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            return;
15965ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov          } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1597ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // external group
1598ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            external_unload_list.push_back(needed);
1599ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else {
1600ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // local group
1601ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            depth_first_list.push_front(needed);
1602ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          }
1603ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        });
16045ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#endif
1605ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      }
16061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1608ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_unload_list.for_each([](soinfo* si) {
1609ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->call_destructors();
1610ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    });
16111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1612ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = local_unload_list.pop_front()) != nullptr) {
1613ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      notify_gdb_of_unload(si);
1614ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      soinfo_free(si);
1615ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1616a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov
1617ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = external_unload_list.pop_front()) != nullptr) {
1618ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      soinfo_unload(si);
1619ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1620ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else {
1621b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1622b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        root->get_realpath(), ref_count);
1623a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov  }
1624a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov}
1625a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov
1626a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
1627052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Use basic string manipulation calls to avoid snprintf.
1628052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1629052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // When debug malloc is enabled, this call returns 0. This in turn causes
1630052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf to do nothing, which causes libraries to fail to load.
1631052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // See b/17302493 for further details.
1632052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Once the above bug is fixed, this code can be modified to use
1633052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf again.
1634052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
1635052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  if (buffer_size < required_len) {
163620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
163720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                 "buffer len %zu, required len %zu", buffer_size, required_len);
1638052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  }
1639052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  char* end = stpcpy(buffer, kDefaultLdPaths[0]);
1640052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  *end = ':';
1641052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  strcpy(end + 1, kDefaultLdPaths[1]);
1642a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes}
1643a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
1644cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
16456bb01b6e6365ced7ca23c9ebecfaf1ea159d5ae2Nick Kralevich  parse_LD_LIBRARY_PATH(ld_library_path);
1646cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
1647cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
16481a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughessoinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
16491b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
1650e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes    DL_ERR("invalid flags to dlopen: %x", flags);
1651851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
1652e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  }
165307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if (extinfo != nullptr) {
165407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
165507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
165607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      return nullptr;
165707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    }
165807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
1659a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov        (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
166020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
166120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
166207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      return nullptr;
166307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    }
1664012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  }
1665279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
1666279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ProtectedDataGuard guard;
16679fb216f844bb15c8e8f27c5ac0490a2f6faacb57Dmitriy Ivanov  soinfo* si = find_library(name, flags, extinfo);
1668851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (si != nullptr) {
1669047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    si->call_constructors();
1670d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1671d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
1672d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
16731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1674b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid do_dlclose(soinfo* si) {
1675279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ProtectedDataGuard guard;
1676b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  soinfo_unload(si);
16771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16799aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
16809aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  typedef ElfW(Addr) (*ifunc_resolver_t)(void);
16819aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
16829aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ElfW(Addr) ifunc_addr = ifunc_resolver();
168320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
168420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
1685c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
16869aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return ifunc_addr;
1687c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
1688c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
16892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
16902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (source_symver < 2 ||
16912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      source_symver >= version_infos.size() ||
16922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      version_infos[source_symver].name == nullptr) {
16932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return nullptr;
16942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
16952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
16962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return &version_infos[source_symver];
16972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
16982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
16992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovvoid VersionTracker::add_version_info(size_t source_index,
17002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                      ElfW(Word) elf_hash,
17012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                      const char* ver_name,
17022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                      const soinfo* target_si) {
17032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (source_index >= version_infos.size()) {
17042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    version_infos.resize(source_index+1);
17052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  version_infos[source_index].elf_hash = elf_hash;
17082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  version_infos[source_index].name = ver_name;
17092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  version_infos[source_index].target_si = target_si;
17102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verneed(const soinfo* si_from) {
17132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  uintptr_t verneed_ptr = si_from->get_verneed_ptr();
17142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (verneed_ptr == 0) {
17162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
17172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  size_t verneed_cnt = si_from->get_verneed_cnt();
17202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
17222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
17232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    size_t vernaux_offset = offset + verneed->vn_aux;
17242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    offset += verneed->vn_next;
17252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verneed->vn_version != 1) {
17272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
17282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
17292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const char* target_soname = si_from->get_string(verneed->vn_file);
17322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    // find it in dependencies
17332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
17348264afb37778bea2a3c6e9aa7144f4877401c3f8Dmitriy Ivanov      return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
17352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    });
17362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (target_si == nullptr) {
17382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
1739b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          target_soname, i, si_from->get_realpath());
17402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
17412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    for (size_t j = 0; j<verneed->vn_cnt; ++j) {
17442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
17452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      vernaux_offset += vernaux->vna_next;
17462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      const ElfW(Word) elf_hash = vernaux->vna_hash;
17482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      const char* ver_name = si_from->get_string(vernaux->vna_name);
17492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      ElfW(Half) source_index = vernaux->vna_other;
17502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      add_version_info(source_index, elf_hash, ver_name, target_si);
17522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
17562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verdef(const soinfo* si_from) {
17592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return for_each_verdef(si_from,
17602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
17612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      add_version_info(verdef->vd_ndx, verdef->vd_hash,
17622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov          si_from->get_string(verdaux->vda_name), si_from);
17632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
17642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  );
17662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init(const soinfo* si_from) {
17692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!si_from->has_min_version(2)) {
17702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
17712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return init_verneed(si_from) && init_verdef(si_from);
17742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1776114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanovbool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
1777114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov                                 const char* sym_name, const version_info** vi) {
1778114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
1779114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
1780114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1781114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
1782114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    *vi = version_tracker.get_version_info(sym_ver);
1783114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1784114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    if (*vi == nullptr) {
1785114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      DL_ERR("cannot find verneed/verdef for version index=%d "
1786b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
1787114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      return false;
1788114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    }
1789114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  } else {
1790114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    // there is no version info
1791114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    *vi = nullptr;
1792114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  }
1793114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1794114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  return true;
1795114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov}
1796114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1797bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#if !defined(__mips__)
17984eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
1799bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
1800bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov  return rela->r_addend;
1801bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov}
1802bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#else
1803bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
180420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov  if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
180520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
1806bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
1807bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov  }
1808bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov  return 0;
1809bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov}
1810bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif
1811bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov
1812fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanovtemplate<typename ElfRelIteratorT>
1813f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanovbool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
1814f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov                      const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
1815fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov  for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
1816fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov    const auto rel = rel_iterator.next();
181718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    if (rel == nullptr) {
181818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      return false;
181918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    }
182018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
1821bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
1822bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
1823bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov
1824bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
18250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    ElfW(Addr) sym_addr = 0;
1826851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    const char* sym_name = nullptr;
1827bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Addr) addend = get_addend(rel, reloc);
1828c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1829b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
1830cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov    if (type == R_GENERIC_NONE) {
1831c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      continue;
1832c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
183314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
18342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Sym)* s = nullptr;
183514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* lsi = nullptr;
183614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1837c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    if (sym != 0) {
1838047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      sym_name = get_string(symtab_[sym].st_name);
1839114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      const version_info* vi = nullptr;
18402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1841114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
1842114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov        return false;
1843114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      }
18442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1845114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
1846114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov        return false;
18472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
1848114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1849851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov      if (s == nullptr) {
1850c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We only allow an undefined symbol if this is a weak reference...
1851047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        s = &symtab_[sym];
1852c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
1853b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
1854114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov          return false;
1855c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1856c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1857c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        /* IHI0044C AAELF 4.5.1.1:
1858c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1859c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           Libraries are not searched to resolve weak references.
1860c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           It is not an error for a weak reference to remain unsatisfied.
1861c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1862c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           During linking, the value of an undefined weak reference is:
1863c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - Zero if the relocation type is absolute
1864c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of the place if the relocation is pc-relative
1865c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of nominal base address if the relocation
1866c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes             type is base-relative.
1867c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes         */
1868c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1869c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        switch (type) {
18701b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_JUMP_SLOT:
18711b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_GLOB_DAT:
18721b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_RELATIVE:
18731b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_IRELATIVE:
1874e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__)
18756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS64:
18766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS32:
18776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS16:
18781b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#elif defined(__x86_64__)
18791b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_X86_64_32:
18801b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_X86_64_64:
1881bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__)
1882bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov          case R_ARM_ABS32:
1883bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__)
1884bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov          case R_386_32:
18851b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#endif
18866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            /*
18876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * The sym_addr was initialized to be zero above, or the relocation
18886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * code below does not care about value of sym_addr.
18896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * No need to do anything.
18906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             */
18916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
18921b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#if defined(__x86_64__)
1893d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov          case R_X86_64_PC32:
1894d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov            sym_addr = reloc;
1895d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov            break;
1896bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__)
1897bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov          case R_386_PC32:
1898bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov            sym_addr = reloc;
1899bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov            break;
1900bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif
19016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          default:
1902bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
1903114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov            return false;
1904c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1905c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      } else {
1906c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We got a definition.
19079aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov        sym_addr = lsi->resolve_symbol_address(s);
1908c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      }
1909c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      count_relocation(kRelocSymbol);
1910c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
1911c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1912c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    switch (type) {
1913cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_JUMP_SLOT:
1914e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1915bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1916bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
1917bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
1918bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
1919bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov
1920bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
1921e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1922cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_GLOB_DAT:
1923e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1924bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1925bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
1926bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
1927bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
1928bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
1929e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1930cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_RELATIVE:
1931cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1932bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1933bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
1934bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
193518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                   reinterpret_cast<void*>(load_bias + addend));
193618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
1937cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1938cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_IRELATIVE:
1939cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1940bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1941bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
1942bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                    reinterpret_cast<void*>(reloc),
194318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                    reinterpret_cast<void*>(load_bias + addend));
194418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend);
1945cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1946cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1947cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__aarch64__)
19486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS64:
1949e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1950bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
19510266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
1952bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
1953bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
1954e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
19556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS32:
1956e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1957bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
19580266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
1959bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
196020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
196120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
196220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
196320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
196420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
196520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + (sym_addr + addend)) <= max_value)) {
196620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
196720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
196820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
196920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   (reloc_value + (sym_addr + addend)), min_value, max_value);
197020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
197120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
1972e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1973e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
19746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS16:
1975e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1976bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
19770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
1978bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
197920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
198020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
198120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
198220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
198320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
198420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + (sym_addr + addend)) <= max_value)) {
198520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
198620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
198720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
198820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + (sym_addr + addend), min_value, max_value);
198920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
199020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
1991e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1992e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
19936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL64:
1994e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
1995bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
19960266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
1997bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
1998bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset;
1999e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL32:
2001e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2002bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20030266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
2004bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
200520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
200620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
200720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
200820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
200920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
201020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
201120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
201220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
201320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
201420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
201520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
201620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2017e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2018e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL16:
2020e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2021bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
2023bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
202420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
202520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
202620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
202720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
202820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
202920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
203020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
203120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
203220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
203320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
203420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
203520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2036e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2037e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
2038e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
20396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_COPY:
204076e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich        /*
204176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * ET_EXEC is not supported so this should not happen.
204276e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
2043aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
204476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
2045aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * Section 4.6.11 "Dynamic relocations"
204676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * R_AARCH64_COPY may only appear in executable objects where e_type is
204776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * set to ET_EXEC.
204876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         */
2049b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
2050114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov        return false;
20516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_TPREL64:
20520266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
2053bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset);
2054e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_DTPREL32:
20560266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
2057bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset);
2058e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
2059e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__)
20606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_32:
20616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2062bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
20646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
2065bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
20666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_64:
20686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2069bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
20716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
2072bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
20736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_PC32:
20756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2076bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
20786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
20796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
2080bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc;
20816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2082bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__)
20836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_ABS32:
20846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
20856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
20866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
20876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
20886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_REL32:
20906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
20916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
20926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
20936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, sym_addr, rel->r_offset, sym_name);
20946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
20956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_COPY:
20976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        /*
20986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * ET_EXEC is not supported so this should not happen.
20996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
21006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
21016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
2102aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * Section 4.6.1.10 "Dynamic relocations"
21036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * R_ARM_COPY may only appear in executable objects where e_type is
21046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * set to ET_EXEC.
21056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         */
2106b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
2107114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov        return false;
21084eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
21096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_32:
21106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
21136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
21146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_PC32:
21166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
21196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
21206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
21216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21224eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
21236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
21246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
21256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2126d7daacb46372132ae3f0121647074936c304b572Raghu Gandham    }
21276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
2129d7daacb46372132ae3f0121647074936c304b572Raghu Gandham}
2130114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#endif  // !defined(__mips__)
2131d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
213220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid soinfo::call_array(const char* array_name __unused, linker_function_t* functions,
213320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                        size_t count, bool reverse) {
2134851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (functions == nullptr) {
2135d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2136d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
21378215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2138b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath());
21398215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2140ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int begin = reverse ? (count - 1) : 0;
2141ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int end = reverse ? -1 : count;
2142ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int step = reverse ? -1 : 1;
21438215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2144ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  for (int i = begin; i != end; i += step) {
2145ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
2146047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    call_function("function", functions[i]);
2147d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2148d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2149b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath());
21501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
21511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2152047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_function(const char* function_name __unused, linker_function_t function) {
2153851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
2154d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2155d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2156d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2157b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath());
2158d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  function();
2159b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath());
21609181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov}
21619181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
2162047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_pre_init_constructors() {
21638147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
21648147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // but ignored in a shared library.
2165047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false);
2166d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
2167e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
2168047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_constructors() {
2169d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  if (constructors_called) {
2170d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2171d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2172e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
2173d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // We set constructors_called before actually calling the constructors, otherwise it doesn't
2174d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // protect against recursive constructor calls. One simple example of constructor recursion
2175d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
2176d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 1. The program depends on libc, so libc's constructor is called here.
2177d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
2178d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 3. dlopen() calls the constructors on the newly created
2179d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    soinfo for libc_malloc_debug_leak.so.
2180d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 4. The debug .so depends on libc, so CallConstructors is
2181d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    called again with the libc soinfo. If it doesn't trigger the early-
2182d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    out above, the libc constructor will be called again (recursively!).
2183d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  constructors_called = true;
2184d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2185ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!is_main_executable() && preinit_array_ != nullptr) {
21868147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes    // The GNU dynamic linker silently ignores these, but we warn the developer.
2187c620059479c47a78d57086d73726c9adc2f337adElliott Hughes    PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
2188b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          get_realpath(), preinit_array_count_);
2189d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
21901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2191d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  get_children().for_each([] (soinfo* si) {
2192047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    si->call_constructors();
2193d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
21941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2195b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("\"%s\": calling constructors", get_realpath());
21968147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
21978147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_INIT should be called before DT_INIT_ARRAY if both are present.
2198047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_INIT", init_func_);
2199047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false);
2200e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov}
22018215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2202047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_destructors() {
220314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!constructors_called) {
220414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return;
220514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
2206b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("\"%s\": calling destructors", get_realpath());
22078147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22088147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI_ARRAY must be parsed in reverse order.
2209047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
22108147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22118147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI should be called after DT_FINI_ARRAY if both are present.
2212047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_FINI", fini_func_);
2213b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
2214b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // This is needed on second call to dlopen
2215b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // after library has been unloaded with RTLD_NODELETE
2216b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  constructors_called = false;
22171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
22181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2219d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) {
22200d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2221047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.push_back(this);
2222047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->children_.push_back(child);
2223d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2224d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2225d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2226d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() {
22270d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (!has_min_version(0)) {
2228d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    return;
2229d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2230d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2231d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 1. Untie connected soinfos from 'this'.
2232047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.for_each([&] (soinfo* child) {
2233047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.remove_if([&] (const soinfo* parent) {
2234d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return parent == this;
2235d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
2236d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
2237d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2238047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.for_each([&] (soinfo* parent) {
2239047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    parent->children_.remove_if([&] (const soinfo* child) {
2240d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return child == this;
2241d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
2242d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
2243d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2244d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 2. Once everything untied - clear local lists.
2245047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.clear();
2246047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.clear();
2247d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2248d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2249d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovdev_t soinfo::get_st_dev() const {
22500d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2251047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_dev_;
2252d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2253d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
22540d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
2255d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov};
2256d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2257d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovino_t soinfo::get_st_ino() const {
22580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2259047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_ino_;
2260d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2261d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
22620d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
2263d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2264d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2265d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovoff64_t soinfo::get_file_offset() const {
226607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if (has_min_version(1)) {
2267047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return file_offset_;
226807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  }
226907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
227007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  return 0;
227107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov}
227207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
2273d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_rtld_flags() const {
2274e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if (has_min_version(1)) {
2275047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return rtld_flags_;
2276e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  }
2277e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
2278e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  return 0;
2279e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
2280e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
2281d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_dt_flags_1() const {
2282d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
2283047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return dt_flags_1_;
2284d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
2285d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2286d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return 0;
2287d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
2288618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
2289d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovvoid soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
2290d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
2291d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
2292047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_GLOBAL;
2293d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
2294d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2295d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_NODELETE) != 0) {
2296047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_NODELETE;
2297d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
2298d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2299047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    dt_flags_1_ = dt_flags_1;
2300d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
2301d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
2302d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2303aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_realpath() const {
230469a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__)
2305aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (has_min_version(2)) {
2306aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return realpath_.c_str();
2307aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  } else {
2308aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return old_name_;
2309aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
2310aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
2311aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return realpath_.c_str();
2312aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
2313aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
2314aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
2315aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_soname() const {
231669a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__)
2317618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  if (has_min_version(2)) {
2318618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    return soname_;
2319618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  } else {
2320aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return old_name_;
2321618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  }
2322aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
2323aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return soname_;
2324aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
2325618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov}
2326618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
232714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if
2328d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set.
2329d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list;
2330d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2331d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() {
23320d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2333047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return children_;
2334d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2335d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
23360d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return g_empty_list;
2337d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2338d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
23392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst soinfo::soinfo_list_t& soinfo::get_children() const {
23402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(0)) {
23412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return children_;
23422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
23432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
23442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return g_empty_list;
23452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
23462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
234714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() {
2348047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(0)) {
2349047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return parents_;
235014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
235114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
2352047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return g_empty_list;
235314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
235414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23552a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
23569aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
23579aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov    return call_ifunc_resolver(s->st_value + load_bias);
23589aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  }
23599aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
23609aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return static_cast<ElfW(Addr)>(s->st_value + load_bias);
23619aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov}
23629aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
23636cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const {
2364047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(1) && (index >= strtab_size_)) {
2365aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
2366b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        get_realpath(), strtab_size_, index);
23676cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov  }
23686cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2369047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return strtab_ + index;
23706cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov}
23716cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2372ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovbool soinfo::is_gnu_hash() const {
2373ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_GNU_HASH) != 0;
2374ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
2375ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
23761b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const {
2377d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
23781b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
2379d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2380ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_linked() const {
2381ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_LINKED) != 0;
2382ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2383ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2384ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_main_executable() const {
2385ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_EXE) != 0;
2386ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2387ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2388ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linked() {
2389ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKED;
2390ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2391ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2392ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linker_flag() {
2393ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKER;
2394ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2395ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2396ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_main_executable() {
2397ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_EXE;
2398ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2399ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2400ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::increment_ref_count() {
2401ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_->ref_count_++;
2402ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2403ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2404ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsize_t soinfo::decrement_ref_count() {
2405ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return --local_group_root_->ref_count_;
2406ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2407ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2408ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsoinfo* soinfo::get_local_group_root() const {
2409ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return local_group_root_;
2410ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2411ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
241204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// This function returns api-level at the time of
241304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// dlopen/load. Note that libraries opened by system
241404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// will always have 'current' api level.
241504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanovuint32_t soinfo::get_target_sdk_version() const {
241604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (!has_min_version(2)) {
241704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    return __ANDROID_API__;
241804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  }
241904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
242004f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  return local_group_root_->target_sdk_version_;
242104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov}
242204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
24231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with
24241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   /dev/null. */
24255419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic int nullify_closed_stdio() {
24266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int dev_null, i, status;
24276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int return_value = 0;
24281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
24306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dev_null < 0) {
24316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("cannot open /dev/null: %s", strerror(errno));
24326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return -1;
24336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null);
24356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
24366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* If any of the stdio file descriptors is valid and not associated
24376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov     with /dev/null, dup /dev/null to it.  */
24386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (i = 0; i < 3; i++) {
24396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* If it is /dev/null already, we are done. */
24406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (i == dev_null) {
24416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
24421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
24431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE("[ Nullifying stdio file descriptor %d]", i);
24456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
24461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* If file is opened, we are good. */
24486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status != -1) {
24496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
24506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
24511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* The only error we allow is that the file descriptor does not
24536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       exist, in which case we dup /dev/null to it. */
24546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (errno != EBADF) {
24556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("fcntl failed: %s", strerror(errno));
24566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
24576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
24586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
24591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    /* Try dupping /dev/null to this stdio file descriptor and
24616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       repeat if there is a signal.  Note that any errors in closing
24626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov       the stdio descriptor are lost.  */
24636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
24646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (status < 0) {
24656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("dup2 failed: %s", strerror(errno));
24666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
24676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      continue;
24681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
24696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* If /dev/null is not one of the stdio file descriptors, close it. */
24726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dev_null > 2) {
24736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null);
2474fa7ba6227f918dadca787a78ed3269bf86fd234dElliott Hughes    if (close(dev_null) == -1) {
24756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("close failed: %s", strerror(errno));
24766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return_value = -1;
24771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
24786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
24806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return return_value;
24811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
24821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2483047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::prelink_image() {
2484e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  /* Extract dynamic section */
2485e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  ElfW(Word) dynamic_flags = 0;
2486e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
2487498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov
24886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can't log anything until the linker is relocated */
2489ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
24906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!relocating_linker) {
249153ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov    INFO("[ linking %s ]", get_realpath());
2492ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
24936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
24956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dynamic == nullptr) {
2496b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    if (!relocating_linker) {
2497b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
2498b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    }
24996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
25006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
25016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (!relocating_linker) {
25026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DEBUG("dynamic = %p", dynamic);
250363f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner    }
25046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
250563f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
25064eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
25076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
25086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                  &ARM_exidx, &ARM_exidx_count);
250963f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif
251063f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
25116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract useful information from dynamic section.
2512618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // Note that: "Except for the DT_NULL element at the end of the array,
2513618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // and the relative order of DT_NEEDED elements, entries may appear in any order."
2514618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  //
2515618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
25166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  uint32_t needed_count = 0;
25176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
25186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
25196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
25206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    switch (d->d_tag) {
25214a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SONAME:
2522618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov        // this is parsed after we have strtab initialized (see below).
25234a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2524ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_HASH:
2526047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2527047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2528047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2529047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
25306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2531ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2532ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      case DT_GNU_HASH:
25333597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov        gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2534ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // skip symndx
2535047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2536047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
2537ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2538047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
25393597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov        gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
2540ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // amend chain for symndx = header[1]
254120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
254220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2543ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2544047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        if (!powerof2(gnu_maskwords_)) {
254520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
2546aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov              gnu_maskwords_, get_realpath());
2547ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          return false;
2548ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        }
2549047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        --gnu_maskwords_;
2550ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2551ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        flags_ |= FLAG_GNU_HASH;
2552ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        break;
2553ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
25546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_STRTAB:
2555047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
25566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2557ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25586cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_STRSZ:
2559047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_size_ = d->d_un.d_val;
25606cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
2561ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMTAB:
2563047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
25646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2565ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SYMENT:
25674a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Sym))) {
2568aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2569aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov              static_cast<size_t>(d->d_un.d_val), get_realpath());
25704a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
25714a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
25724a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2573ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTREL:
2575513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA)
2576513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        if (d->d_un.d_val != DT_RELA) {
2577aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
2578513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov          return false;
2579513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        }
2580513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else
25816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val != DT_REL) {
2582aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
25836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
25846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
2585c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
2586513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2587ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_JMPREL:
25894eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2590047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
2591c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2592047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
2593c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
25946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2595ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTRELSZ:
25974eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2598047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
2599c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2600047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
2601c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
26026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2603ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTGOT:
26054a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__)
26066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Used by mips and mips64.
2607047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
2608c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
26094a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // Ignore for other platforms... (because RTLD_LAZY is not supported)
26104a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2611ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_DEBUG:
26136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_DEBUG entry to the address of _r_debug for GDB
26146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // if the dynamic table is writable
26159918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64
26169918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree.
261714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as
26189918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable.
26199918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__))
26206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if ((dynamic_flags & PF_W) != 0) {
26216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
26226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
26239918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif
2624c6292ea39cce054175e4f9f797c05aeb8da0ac4bDmitriy Ivanov        break;
26254eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
26266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
2627047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
26286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2629ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELASZ:
2631047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
26326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2633ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
263418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELA:
263518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
263618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
263718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
263818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELASZ:
263918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_size_ = d->d_un.d_val;
264018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
264118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
264218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_REL:
2643aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
264418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
264518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
264618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELSZ:
2647aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
264818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
264918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
26504a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELAENT:
26514a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rela))) {
2652f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
26534a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
26544a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
26554a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2656ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2657ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // ignored (see DT_RELCOUNT comments for details)
26584a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELACOUNT:
26594a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2660ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
2662aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
26636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2664ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
2666aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
26676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
266818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2669c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
26706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
2671047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
26726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2673ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
2675047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
26766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2677ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26784a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELENT:
26794a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rel))) {
2680f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
26814a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
26824a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
26834a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2684ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
268518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_REL:
268618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
268718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
268818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
268918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELSZ:
269018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_size_ = d->d_un.d_val;
269118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
269218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
269318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELA:
2694aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
269518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
269618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
269718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELASZ:
2698aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
269918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
270018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2701ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // "Indicates that all RELATIVE relocations have been concatenated together,
2702ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // and specifies the RELATIVE relocation count."
2703ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      //
2704ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // TODO: Spec also mentions that this can be used to optimize relocation process;
2705ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Not currently used by bionic linker - ignored.
27064a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELCOUNT:
27074a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
270818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
27096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
2710aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
27116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
271218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
271318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_RELASZ:
2714aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
271518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
271618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2717c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
27186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT:
2719047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2720aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
27216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2722ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI:
2724047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2725aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
27266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2727ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAY:
2729047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2730aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
27316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2732ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAYSZ:
27341649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2736ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAY:
2738047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2739aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
27406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2741ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAYSZ:
27431649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2745ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAY:
2747047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2748aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
27496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2750ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAYSZ:
27521649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2754ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_TEXTREL:
275656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__)
2757aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
27586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
275956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else
276056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov        has_text_relocations = true;
276156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov        break;
276256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
2763ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMBOLIC:
276596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        has_DT_SYMBOLIC = true;
27666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2767ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_NEEDED:
27696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        ++needed_count;
27706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2771ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FLAGS:
27736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val & DF_TEXTREL) {
277456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__)
2775aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
27766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
277756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else
277856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov          has_text_relocations = true;
277956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
27806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
278196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        if (d->d_un.d_val & DF_SYMBOLIC) {
278296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov          has_DT_SYMBOLIC = true;
278396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        }
27846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2785ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27866cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_FLAGS_1:
2787d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        set_dt_flags_1(d->d_un.d_val);
27886cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2789d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
2790ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov          DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
27916cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        }
27926cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
27934eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
27946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_MAP:
27956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
27966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        {
27976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
27986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *dp = &_r_debug;
27996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
28006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2801688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham      case DT_MIPS_RLD_MAP2:
2802688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
2803688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        {
280420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(
280520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
2806688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham          *dp = &_r_debug;
2807688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        }
2808688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        break;
2809ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
28106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_VERSION:
28116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_FLAGS:
28126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_BASE_ADDRESS:
28136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_UNREFEXTNO:
28146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2815d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_SYMTABNO:
2817047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_symtabno_ = d->d_un.d_val;
28186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2819d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_LOCAL_GOTNO:
2821047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_local_gotno_ = d->d_un.d_val;
28226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2823d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_GOTSYM:
2825047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_gotsym_ = d->d_un.d_val;
28266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
28274eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
2828ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2829ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      case DT_BIND_NOW:
2830ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov        break;
2831ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2832513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERSYM:
28332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
28342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2836513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEF:
28372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verdef_ptr_ = load_bias + d->d_un.d_ptr;
28382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
2839513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEFNUM:
28402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verdef_cnt_ = d->d_un.d_val;
28412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2843e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEED:
28442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verneed_ptr_ = load_bias + d->d_un.d_ptr;
28452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2847e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEEDNUM:
28482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verneed_cnt_ = d->d_un.d_val;
2849513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2850d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
28528f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        if (!relocating_linker) {
2853aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
28548f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov              reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
28558f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        }
28566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
28571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
28586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
28591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
28606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
2861047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        reinterpret_cast<void*>(base), strtab_, symtab_);
28621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
28636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Sanity checks.
28646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (relocating_linker && needed_count != 0) {
28656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
28666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
28683597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  if (nbucket_ == 0 && gnu_nbucket_ == 0) {
2869aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
2870b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        "(new hash type from the future?)", get_realpath());
28716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2873047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (strtab_ == 0) {
2874b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
28756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2877047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (symtab_ == 0) {
2878b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
28796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
288138c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov
288207f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  // second pass - parse entries relying on strtab
288307f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
288407f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov    if (d->d_tag == DT_SONAME) {
288507f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      soname_ = get_string(d->d_un.d_val);
288607f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#if defined(__work_around_b_19059885__)
288707f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      strlcpy(old_name_, soname_, sizeof(old_name_));
288807f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#endif
288907f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      break;
289007f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov    }
289107f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  }
289207f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov
289338c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // Before M release linker was using basename in place of soname.
289404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // In the case when dt_soname is absent some apps stop working
289538c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // because they can't find dt_needed library by soname.
289638c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // This workaround should keep them working. (applies only
289704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // for apps targeting sdk version <=22). Make an exception for
289804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // the main executable and linker; they do not need to have dt_soname
289904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
290004f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov      get_application_target_sdk_version() <= 22) {
290138c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov    soname_ = basename(realpath_.c_str());
290238c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov    DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
290338c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov        get_realpath(), soname_);
290438c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  }
29056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
290614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
29071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
290818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovbool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
290918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                        const android_dlextinfo* extinfo) {
29101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2911ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_ = local_group.front();
2912ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (local_group_root_ == nullptr) {
2913ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_group_root_ = this;
2914ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
2915ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
291604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
291704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    target_sdk_version_ = get_application_target_sdk_version();
291804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  }
291904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
2920f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  VersionTracker version_tracker;
2921f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov
2922f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  if (!version_tracker.init(this)) {
2923f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    return false;
2924f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  }
2925f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov
292656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__)
292756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  if (has_text_relocations) {
292856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // Make segments writable to allow text relocations to work properly. We will later call
292956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
293056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    DL_WARN("%s has text relocations. This is wasting memory and prevents "
2931b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov            "security hardening. Please fix.", get_realpath());
293256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
293356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2934b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
293556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      return false;
293656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    }
293756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  }
293856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
293956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov
294018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov  if (android_relocs_ != nullptr) {
294118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    // check signature
294218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    if (android_relocs_size_ > 3 &&
294318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[0] == 'A' &&
294418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[1] == 'P' &&
294518870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov        android_relocs_[2] == 'S' &&
294618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[3] == '2') {
2947b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      DEBUG("[ android relocating %s ]", get_realpath());
294818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
294918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      bool relocated = false;
295018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      const uint8_t* packed_relocs = android_relocs_ + 4;
295118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      const size_t packed_relocs_size = android_relocs_size_ - 4;
295218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
295318870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov      relocated = relocate(
2954f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov          version_tracker,
295518870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov          packed_reloc_iterator<sleb128_decoder>(
295618870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov            sleb128_decoder(packed_relocs, packed_relocs_size)),
295718870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov          global_group, local_group);
295818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
295918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      if (!relocated) {
296018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
296118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      }
296218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    } else {
296318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      DL_ERR("bad android relocation header.");
296418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      return false;
296518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    }
296618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov  }
296718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
29684eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2969047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rela_ != nullptr) {
2970b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s ]", get_realpath());
2971f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2972f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
29736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2974c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
29756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2976047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rela_ != nullptr) {
2977b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s plt ]", get_realpath());
2978f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2979f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
29806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
29811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
29826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
29839aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else
2984047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rel_ != nullptr) {
2985b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s ]", get_realpath());
2986f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2987f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
29886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
29891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
29906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2991047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rel_ != nullptr) {
2992b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s plt ]", get_realpath());
2993f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2994f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
29956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2996c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith    }
29976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
29989aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif
2999c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
30004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
3001dc145b510640202a60b0dfaef9d56cd8fc1c05a9Dmitriy Ivanov  if (!mips_relocate_got(version_tracker, global_group, local_group)) {
30026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
30036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3004d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif
3005d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
3006b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  DEBUG("[ finished linking %s ]", get_realpath());
30071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
300856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__)
300956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  if (has_text_relocations) {
301056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // All relocations are done, we can protect our segments back to read-only.
301156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
301256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      DL_ERR("can't protect segments for \"%s\": %s",
3013b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
301456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      return false;
301556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    }
301656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  }
301756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
301856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov
30196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can also turn on GNU RELRO protection */
30206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
30216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3022b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov           get_realpath(), strerror(errno));
30236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
30246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
30259ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich
30266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Handle serializing/sharing the RELRO segment */
30276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
30286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
30296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                       extinfo->relro_fd) < 0) {
30306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
3031b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
30326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
3033183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)    }
30346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
30356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
30366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                 extinfo->relro_fd) < 0) {
30376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
3038b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
30396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
30406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
30416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3042183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)
30436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  notify_gdb_of_load(this);
30446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
30451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
30461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3047468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
3048c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list.
3049c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers.
3050c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc.
3051c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */
3052812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) {
30534eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR)
30540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
3055851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (ehdr_vdso == nullptr) {
30560266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    return;
30570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
3058c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
305907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0);
3060ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
30610266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
30620266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phnum = ehdr_vdso->e_phnum;
30630266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
30640266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
30650266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
3066ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
3067047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->prelink_image();
3068047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr);
3069c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif
3070c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
3071c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
3072c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/*
3073d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below.
3074d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
30750d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__)
30760d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64"
30770d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else
30780d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker"
30790d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif
3080aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
3081aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// This is done to avoid calling c-tor prematurely
3082aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// because soinfo c-tor needs memory allocator
3083aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// which might be initialized after global variables.
3084aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic uint8_t linker_soinfo_for_gdb_buf[sizeof(soinfo)] __attribute__((aligned(8)));
3085aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic soinfo* linker_soinfo_for_gdb = nullptr;
3086d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3087d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list.
3088d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text"
3089d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to
3090d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
3091d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't
3092d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list.
3093d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
3094d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
3095aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0);
3096aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
3097aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  linker_soinfo_for_gdb->base = linker_base;
3098d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3099d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  /*
3100d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * Set the dynamic field in the link map otherwise gdb will complain with
3101d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * the following:
3102d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   warning: .dynamic section for "/system/bin/linker" is not at the
3103d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   expected address (wrong library or version mismatch?)
3104d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   */
3105d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
3106d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
3107d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
3108aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov                                 &linker_soinfo_for_gdb->dynamic, nullptr);
3109aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
3110d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
3111d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
31120b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanovextern "C" int __system_properties_init(void);
31130b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov
3114d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/*
3115468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and
3116468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs
3117468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point.
3118468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
31190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
31201a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING
31216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  struct timeval t0, t1;
31226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t0, 0);
31231a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif
31241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Initialize environment functions, and get to the ELF aux vectors table.
31266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  linker_env_init(args);
3127be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
31280b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov  // Initialize system properties
31290b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov  __system_properties_init(); // may use 'environ'
31300b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov
31316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // If this is a setuid/setgid program, close the security hole described in
31326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
31336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (get_AT_SECURE()) {
31346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    nullify_closed_stdio();
31356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31368d3e91d4f842911366155845afb3cfbdad0b4cadNick Kralevich
31376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  debuggerd_init();
31381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Get a few environment variables.
31406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* LD_DEBUG = linker_env_get("LD_DEBUG");
31416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (LD_DEBUG != nullptr) {
31426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    g_ld_debug_verbosity = atoi(LD_DEBUG);
31436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3144be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
31456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Normally, these are cleaned by linker_env_init, but the test
31466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // doesn't cost us anything.
31476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpath_env = nullptr;
31486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpreload_env = nullptr;
31496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!get_AT_SECURE()) {
31506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ldpath_env = linker_env_get("LD_LIBRARY_PATH");
31516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ldpreload_env = linker_env_get("LD_PRELOAD");
31526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3154bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#if !defined(__LP64__)
3155bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov  if (personality(PER_LINUX32) == -1) {
3156bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov    __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
3157bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov  }
3158bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#endif
3159bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov
31606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  INFO("[ android linker & debugger ]");
31611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
316207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
31636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
31646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
31656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* bootstrap the link map, the main exe always needs to be first */
3168ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  si->set_main_executable();
31696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(si->link_map_head);
31701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = 0;
31726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_name = args.argv[0];
31736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_prev = nullptr;
31746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_next = nullptr;
31751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_map = map;
31776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
31781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  init_linker_info_for_gdb(linker_base);
31801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract information passed from the kernel.
31826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
31836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phnum = args.getauxval(AT_PHNUM);
31846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->entry = args.getauxval(AT_ENTRY);
31851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Compute the value of si->base. We can't rely on the fact that
31876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * the first entry is the PHDR because this will not be true
31886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * for certain executables (e.g. some in the NDK unit test suite)
31896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   */
31906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->base = 0;
31916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
31926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->load_bias = 0;
31936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t i = 0; i < si->phnum; ++i) {
31946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (si->phdr[i].p_type == PT_PHDR) {
31956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
31966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
31976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
31988180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner    }
31996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->dynamic = nullptr;
32011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
32026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
32036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (elf_hdr->e_type != ET_DYN) {
32046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n");
32056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
32066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32072aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich
32086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
32096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_LIBRARY_PATH(ldpath_env);
32106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_PRELOAD(ldpreload_env);
32114fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
32126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  somain = si;
32135ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel
32146718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  if (!si->prelink_image()) {
32156718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
32166718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    exit(EXIT_FAILURE);
32176718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  }
321814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
3219d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // add somain to global group
3220d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
3221d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
32226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Load ld_preloads and dependencies.
32236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  StringLinkedList needed_library_name_list;
32246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t needed_libraries_count = 0;
32256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t ld_preloads_count = 0;
3226d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
3227d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (const auto& ld_preload_name : g_ld_preload_names) {
3228d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    needed_library_name_list.push_back(ld_preload_name.c_str());
32296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
323053ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov    ++ld_preloads_count;
32316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
323214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
32336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for_each_dt_needed(si, [&](const char* name) {
32346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    needed_library_name_list.push_back(name);
32356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
32366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  });
323714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
32386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* needed_library_names[needed_libraries_count];
323914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
32406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  memset(needed_library_names, 0, sizeof(needed_library_names));
32416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
324214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
3243d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  if (needed_libraries_count > 0 &&
3244d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      !find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
3245d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov          &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
32466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
32476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
3248ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else if (needed_libraries_count == 0) {
3249ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
3250ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
3251ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      exit(EXIT_FAILURE);
3252ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
3253ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    si->increment_ref_count();
32546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
32566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  add_vdso(args);
3257c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
3258279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  {
3259279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    ProtectedDataGuard guard;
32609181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
3261279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    si->call_pre_init_constructors();
3262279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
3263279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    /* After the prelink_image, the si->load_bias is initialized.
3264279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
3265279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * We need to update this value for so exe here. So Unwind_Backtrace
3266279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * for some arch like x86 could work correctly within so exe.
3267279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     */
3268279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    map->l_addr = si->load_bias;
3269279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    si->call_constructors();
3270279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
3271e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
32721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
32736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t1, nullptr);
32746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
32756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
32766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
32771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
32796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0],
32806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocAbsolute],
32816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocRelative],
32826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocCopy],
32836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocSymbol]);
32841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
32866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  {
32876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned n;
32886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned i;
32896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned count = 0;
32906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    for (n = 0; n < 4096; n++) {
32916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (bitmask[n]) {
32926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        unsigned x = bitmask[n];
3293e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__)
32946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 32; i++) {
3295e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else
32966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 8; i++) {
3297e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif
32986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          if (x & 1) {
32996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            count++;
33006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          }
33016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          x >>= 1;
33021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
33036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
33041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
33056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4);
33066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
33071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
33081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
33091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
33106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  fflush(stdout);
33111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
33121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3313b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry));
33146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return si->entry;
33151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3316468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
3317bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only
3318bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library
3319bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself.
3320bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *
3321bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input:
3322bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    elf    -> address of ELF header, assumed to be at the start of the file.
3323bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return:
3324bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    load bias, i.e. add the value of any p_vaddr in the file to get
3325bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    the corresponding address in memory.
3326bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */
33270266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
33280266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) offset = elf->e_phoff;
3329b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  const ElfW(Phdr)* phdr_table =
3330b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
33310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
3332fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
33330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
3334fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (phdr->p_type == PT_LOAD) {
33350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
3336bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner    }
3337fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
3338fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  return 0;
3339bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner}
3340bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner
3341efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start();
3342efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
3343468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
3344468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This
3345468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and
3346468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation().
3347468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich *
3348468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own
3349468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern
3350468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault.
3351468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
33520266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) {
335342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  KernelArgumentBlock args(raw_args);
335442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
33550266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
3356efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
33570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
3358faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
335942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3360aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  soinfo linker_so(nullptr, nullptr, 0, 0);
336142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3362efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // If the linker is not acting as PT_INTERP entry_point is equal to
3363efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // _start. Which means that the linker is running as an executable and
3364efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // already linked by PT_INTERP.
3365efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  //
3366efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // This happens when user tries to run 'adb shell /system/bin/linker'
3367efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // see also https://code.google.com/p/android/issues/detail?id=63174
3368efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
3369efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
3370efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  }
3371efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
337242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.base = linker_addr;
337342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
337442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
3375851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  linker_so.dynamic = nullptr;
337642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phdr = phdr;
337742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phnum = elf_hdr->e_phnum;
3378ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  linker_so.set_linker_flag();
337942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3380d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // This might not be obvious... The reasons why we pass g_empty_list
3381d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // in place of local_group here are (1) we do not really need it, because
3382d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
3383d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // itself without having to look into local_group and (2) allocators
3384d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // are not yet initialized, and therefore we cannot use linked_list.push_*
3385d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // functions at this point.
3386047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
338742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // It would be nice to print an error message, but if the linker
338842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // can't link itself, there's no guarantee that we'll be able to
3389b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // call write() (because it involves a GOT reference). We may as
3390b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // well try though...
3391b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    const char* msg = "CANNOT LINK EXECUTABLE: ";
3392b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, msg, strlen(msg));
3393b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
3394b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, "\n", 1);
3395b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    _exit(EXIT_FAILURE);
339642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
3397468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
339814241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov  __libc_init_tls(args);
339914241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov
3400efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // Initialize the linker's own global variables
3401047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  linker_so.call_constructors();
34024151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov
34030d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // Initialize static variables. Note that in order to
34040d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // get correct libdl_info we need to call constructors
34050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // before get_libdl_info().
34060d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  solist = get_libdl_info();
34070d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  sonext = get_libdl_info();
34080d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
340942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // We have successfully fixed our own relocations. It's safe to run
341042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // the main part of the linker now.
34111728b2396591853345507a063ed6075dfd251706Elliott Hughes  args.abort_message_ptr = &g_abort_message;
34120266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
34135419b9474753d25dff947c7740532f86d130c0beElliott Hughes
3414611f95689e1012283bd11917003d3740d3ce532dElliott Hughes  INFO("[ jumping to _start ]");
3415611f95689e1012283bd11917003d3740d3ce532dElliott Hughes
341642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // Return the address that the calling assembly stub should jump to.
341742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  return start_address;
3418468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich}
3419