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