linker.cpp revision 28154f5c56dc4a64270cae2374b47a168d1bd7fa
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" 5718870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov#include "linker_sleb128.h" 5823363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h" 59cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#include "linker_relocs.h" 60fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker_reloc_iterators.h" 61aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin#include "ziparchive/zip_archive.h" 621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughesextern void __libc_init_AT_SECURE(KernelArgumentBlock&); 641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6566c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes// Override macros to use C++ style casts. 661649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#undef ELF_ST_TYPE 671649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf) 681649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov 690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); 701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 71600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<soinfo> g_soinfo_allocator; 72600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator; 73ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 74d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist; 75d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext; 766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info 771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 781728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = { 794eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__) 80011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes "/vendor/lib64", 81011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes "/system/lib64", 82011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else 83124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes "/vendor/lib", 84124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes "/system/lib", 85011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif 86851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov nullptr 87124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes}; 88124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes 892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymNotNeeded = 0; 902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymGlobal = 1; 912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 92d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_library_paths; 93d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_preload_names; 94a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 95d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<soinfo*> g_ld_preloads; 964fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 971728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity; 981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 99851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd. 1000d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 102bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t { 1036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int count[kRelocMax]; 104bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}; 105bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 106bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats; 107bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 108114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind kind) { 1096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++linker_stats.count[kind]; 110bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 111bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else 112114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind) { 113bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 117114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovuint32_t bitmask[4096]; 1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1202e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768]; 1212e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 122650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() { 1235419b9474753d25dff947c7740532f86d130c0beElliott Hughes return &__linker_dl_err_buf[0]; 1242e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin} 1252e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 126650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() { 127650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes return sizeof(__linker_dl_err_buf); 128650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes} 129650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes 1306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified 1316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity. 13220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovextern "C" 13320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(); 1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1351728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER; 13620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic r_debug _r_debug = 13720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0}; 13820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov 1393a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0; 1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1413a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) { 1426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Copy the necessary fields into the debug structure. 1436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(info->link_map_head); 1446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = info->load_bias; 145aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov // link_map l_name field is not const. 146aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov map->l_name = const_cast<char*>(info->get_realpath()); 1476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_ld = info->dynamic; 1486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 1496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Stick the new library at the end of the list. 1506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // gdb tends to care more about libc than it does 1516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // about leaf libraries, and ordering it this way 1526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // reduces the back-and-forth over the wire. 1536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (r_debug_tail) { 1546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail->l_next = map; 1556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = r_debug_tail; 1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = 0; 1576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 1586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_map = map; 1596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = 0; 1606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = 0; 1616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map; 1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 165bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) { 1666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(info->link_map_head); 1675e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 1686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (r_debug_tail == map) { 1696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map->l_prev; 1706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1715e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 1726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (map->l_prev) { 1736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev->l_next = map->l_next; 1746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (map->l_next) { 1766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next->l_prev = map->l_prev; 1776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1785e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev} 1795e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 180bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) { 181ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (info->is_main_executable()) { 1826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // GDB already knows about the main executable 1836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 1846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ScopedPthreadMutexLocker locker(&g__r_debug_mutex); 1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_ADD; 1896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov insert_soinfo_into_debug_map(info); 1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_CONSISTENT; 1946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 1955e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev} 1965e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 197bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) { 198ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (info->is_main_executable()) { 1996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // GDB already knows about the main executable 2006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2025e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ScopedPthreadMutexLocker locker(&g__r_debug_mutex); 2045e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_DELETE; 2066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2075e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov remove_soinfo_from_debug_map(info); 2095e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_CONSISTENT; 2116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21418a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() { 2153a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes _r_debug.r_state = r_debug::RT_ADD; 2163a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes rtld_db_dlactivity(); 2173a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes _r_debug.r_state = r_debug::RT_CONSISTENT; 2183a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes rtld_db_dlactivity(); 2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 221d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() { 222d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return g_soinfo_links_allocator.alloc(); 223d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 224d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 225d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) { 226d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov g_soinfo_links_allocator.free(entry); 227d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 228d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 22920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat, 23020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov off64_t file_offset, uint32_t rtld_flags) { 231aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (strlen(name) >= PATH_MAX) { 232ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn DL_ERR("library name \"%s\" too long", name); 233851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 234ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn } 235ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 23607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags); 237d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 238ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext->next = si; 239ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext = si; 2401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 241ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("name %s: allocated soinfo @ %p", name, si); 242ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn return si; 2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 245faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) { 2466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 2476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2494688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 2506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->base != 0 && si->size != 0) { 2516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov munmap(reinterpret_cast<void*>(si->base), si->size); 2526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 253d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo *prev = nullptr, *trav; 2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 256b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si); 2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (trav = solist; trav != nullptr; trav = trav->next) { 2596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == si) { 2606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev = trav; 2636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 264ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == nullptr) { 2666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // si was not in solist 267b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si); 2686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // clear links to/from si 2726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->remove_all_links(); 273d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // prev will never be null, because the first entry in solist is 2756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // always the static libdl_info. 2766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev->next = si->next; 2776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == sonext) { 2786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sonext = prev; 2796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 280d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov 2816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_soinfo_allocator.free(si); 2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 284cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_path(const char* path, const char* delimiters, 285d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov std::vector<std::string>* paths) { 286851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (path == nullptr) { 287cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes return; 288cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 289cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 290d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov paths->clear(); 291cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 292d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov for (const char *p = path; ; ++p) { 293d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov size_t len = strcspn(p, delimiters); 294d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov // skip empty tokens 295d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (len == 0) { 296d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov continue; 297cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 298cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 299d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov paths->push_back(std::string(p, len)); 300d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov p += len; 301d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 302d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (*p == '\0') { 303d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov break; 304d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 305cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 306cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 307cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 308cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_LIBRARY_PATH(const char* path) { 309d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov parse_path(path, ":", &g_ld_library_paths); 310cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 311cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 312cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_PRELOAD(const char* path) { 313cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes // We have historically supported ':' as well as ' ' in LD_PRELOAD. 314d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov parse_path(path, " :", &g_ld_preload_names); 315cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 316cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 317aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic bool realpath_fd(int fd, std::string* realpath) { 318aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX); 319aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd); 320aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) { 321ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd); 322aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return false; 323aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 324aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 325aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov *realpath = std::string(&buf[0]); 326aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return true; 327aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov} 328aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 3294eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 3304688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 3316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// For a given PC, find the .so that it belongs to. 3326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Returns the base address of the .ARM.exidx section 3336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// for that .so, and the number of 8-byte entries 3346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// in that section (via *pcount). 3356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// 3366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Intended to be called by libc's __gnu_Unwind_Find_exidx(). 3376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// 3386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is exposed via dlfcn.cpp and libdl.so. 339faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { 3401649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov uintptr_t addr = reinterpret_cast<uintptr_t>(pc); 3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (soinfo* si = solist; si != 0; si = si->next) { 3436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((addr >= si->base) && (addr < (si->base + si->size))) { 3446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *pcount = si->ARM_exidx_count; 3451649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx); 3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *pcount = 0; 3496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return nullptr; 3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3514688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 35224053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif 3534688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 3546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Here, we only have to provide a callback to iterate across all the 3556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// loaded libraries. gcc_eh does the rest. 356faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesint dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) { 3576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int rv = 0; 3586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 3596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_phdr_info dl_info; 3606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_addr = si->link_map_head.l_addr; 3616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_name = si->link_map_head.l_name; 3626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_phdr = si->phdr; 3636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_phnum = si->phnum; 3646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rv = cb(&dl_info, sizeof(dl_phdr_info), data); 3656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (rv != 0) { 3666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return rv; 3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3714688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 3722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst ElfW(Versym)* soinfo::get_versym(size_t n) const { 3732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2) && versym_ != nullptr) { 3742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return versym_ + n; 3752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 3762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return nullptr; 3782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 3792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3802a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verneed_ptr() const { 3812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 3822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verneed_ptr_; 3832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 3842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 3862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 3872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verneed_cnt() const { 3892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 3902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verneed_cnt_; 3912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 3922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 3942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 3952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3962a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verdef_ptr() const { 3972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 3982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verdef_ptr_; 3992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 4022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 4032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verdef_cnt() const { 4052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 4062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verdef_cnt_; 4072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 4102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 4112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovtemplate<typename F> 4132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic bool for_each_verdef(const soinfo* si, F functor) { 4142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!si->has_min_version(2)) { 4152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 4162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uintptr_t verdef_ptr = si->get_verdef_ptr(); 4192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef_ptr == 0) { 4202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 4212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t offset = 0; 4242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t verdef_cnt = si->get_verdef_cnt(); 4262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov for (size_t i = 0; i<verdef_cnt; ++i) { 4272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset); 4282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t verdaux_offset = offset + verdef->vd_aux; 4292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov offset += verdef->vd_next; 4302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef->vd_version != 1) { 4323d7bea1fa00342f2a18331ea33a4b6e3332b3b02Dmitriy Ivanov DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s", 433b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov i, verdef->vd_version, si->get_realpath()); 4342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 4352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if ((verdef->vd_flags & VER_FLG_BASE) != 0) { 4382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // "this is the version of the file itself. It must not be used for 4392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // matching a symbol. It can be used to match references." 4402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // 4412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // http://www.akkadia.org/drepper/symbol-versioning 4422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov continue; 4432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef->vd_cnt == 0) { 4462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i); 4472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 4482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset); 4512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (functor(i, verdef, verdaux) == true) { 4532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 4542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 4582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 4592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const { 4612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (vi == nullptr) { 4622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *versym = kVersymNotNeeded; 4632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 4642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *versym = kVersymGlobal; 4672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return for_each_verdef(this, 4692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) { 4702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef->vd_hash == vi->elf_hash && 4712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov strcmp(vi->name, get_string(verdaux->vda_name)) == 0) { 4722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *versym = verdef->vd_ndx; 4732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 4742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 4772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ); 4792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 4802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_symbol_by_name(SymbolName& symbol_name, 4822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const version_info* vi, 4832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)** symbol) const { 4842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uint32_t symbol_index; 4852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov bool success = 4862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov is_gnu_hash() ? 4872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov gnu_lookup(symbol_name, vi, &symbol_index) : 4882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov elf_lookup(symbol_name, vi, &symbol_index); 4892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (success) { 4912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index; 4922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 4932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 4942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return success; 495ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 496ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 497ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) { 498ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (ELF_ST_BIND(s->st_info) == STB_GLOBAL || 499ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov ELF_ST_BIND(s->st_info) == STB_WEAK) { 500ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return s->st_shndx != SHN_UNDEF; 501ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) { 502ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'", 503b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath()); 504ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 505ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 506ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return false; 507ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 508ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 5092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymHiddenBit = 0x8000; 5102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 5112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool is_versym_hidden(const ElfW(Versym)* versym) { 5122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // the symbol is hidden if bit 15 of versym is set. 5132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return versym != nullptr && (*versym & kVersymHiddenBit) != 0; 5142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 5152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 5162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool check_symbol_version(const ElfW(Versym) verneed, 5172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Versym)* verdef) { 5182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verneed == kVersymNotNeeded || 5192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef == nullptr || 5202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed == (*verdef & ~kVersymHiddenBit); 5212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 5222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 5232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::gnu_lookup(SymbolName& symbol_name, 5242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const version_info* vi, 5252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uint32_t* symbol_index) const { 526ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t hash = symbol_name.gnu_hash(); 527047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov uint32_t h2 = hash >> gnu_shift2_; 5281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 529ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8; 530047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_; 531047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num]; 5321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = 0; 5342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 5353597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)", 536b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 5373597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 538ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // test against bloom filter 539ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) { 5403597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p", 541b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 5423597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 5432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 544ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 545ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 546ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // bloom test says "probably yes"... 5473597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov uint32_t n = gnu_bucket_[hash % gnu_nbucket_]; 548ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 549ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (n == 0) { 5503597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p", 551b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 5523597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 5532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 5542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 5552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 5562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // lookup versym for the version definition in this library 5572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // note the difference between "version is not requested" (vi == nullptr) 5582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // and "version not found". In the first case verneed is kVersymNotNeeded 5592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // which implies that the default version can be accepted; the second case results in 5602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols 5612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // for this library and consider only *global* ones. 5622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Versym) verneed = 0; 5632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!find_verdef_version_index(vi, &verneed)) { 5642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 565ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 566ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 567ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov do { 568047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* s = symtab_ + n; 5692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Versym)* verdef = get_versym(n); 5702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // skip hidden versions when verneed == kVersymNotNeeded (0) 5712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) { 5722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov continue; 5732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 5743597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov if (((gnu_chain_[n] ^ hash) >> 1) == 0 && 5752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov check_symbol_version(verneed, verdef) && 576ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 && 577ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov is_symbol_global_and_defined(this, s)) { 5783597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", 579b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value), 5803597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov static_cast<size_t>(s->st_size)); 5812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = n; 5822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 583ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 5843597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov } while ((gnu_chain_[n++] & 1) == 0); 5853597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 5863597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p", 587b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 5881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 590ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 591ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 5922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::elf_lookup(SymbolName& symbol_name, 5932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const version_info* vi, 5942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uint32_t* symbol_index) const { 595ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t hash = symbol_name.elf_hash(); 596ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 597ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd", 598b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), 599aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov reinterpret_cast<void*>(base), hash, hash % nbucket_); 600ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 6012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Versym) verneed = 0; 6022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!find_verdef_version_index(vi, &verneed)) { 6032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 6042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 606047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) { 607047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* s = symtab_ + n; 6082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Versym)* verdef = get_versym(n); 6092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // skip hidden versions when verneed == 0 6112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) { 6122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov continue; 6132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (check_symbol_version(verneed, verdef) && 6162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 && 61720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov is_symbol_global_and_defined(this, s)) { 618ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", 619b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), 620aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov reinterpret_cast<void*>(s->st_value), 621aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov static_cast<size_t>(s->st_size)); 6222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = n; 6232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 6241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 6250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 6261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 627aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd", 628b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov symbol_name.get_name(), get_realpath(), 629aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov reinterpret_cast<void*>(base), hash, hash % nbucket_); 630aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 6312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = 0; 6322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 6331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 635aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovsoinfo::soinfo(const char* realpath, const struct stat* file_stat, 63620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov off64_t file_offset, int rtld_flags) { 6370d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov memset(this, 0, sizeof(*this)); 6380d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 639aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (realpath != nullptr) { 640aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov realpath_ = realpath; 641aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 642aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 643ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ = FLAG_NEW_SOINFO; 644047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov version_ = SOINFO_VERSION; 6450d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 646851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (file_stat != nullptr) { 647047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->st_dev_ = file_stat->st_dev; 648047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->st_ino_ = file_stat->st_ino; 649047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->file_offset_ = file_offset; 6500d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov } 651e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 652047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->rtld_flags_ = rtld_flags; 6530d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov} 6540d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 6556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 656ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::elf_hash() { 657ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (!has_elf_hash_) { 658aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov const uint8_t* name = reinterpret_cast<const uint8_t*>(name_); 659ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t h = 0, g; 660ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 661ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov while (*name) { 662ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov h = (h << 4) + *name++; 663ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov g = h & 0xf0000000; 664ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov h ^= g; 665ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov h ^= g >> 24; 666ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 667ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 668ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov elf_hash_ = h; 669ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov has_elf_hash_ = true; 6706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 671ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 672ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return elf_hash_; 673ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 674ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 675ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::gnu_hash() { 676ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (!has_gnu_hash_) { 677ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t h = 5381; 678aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov const uint8_t* name = reinterpret_cast<const uint8_t*>(name_); 679ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov while (*name != 0) { 680ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c 681ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 682ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 683ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov gnu_hash_ = h; 684ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov has_gnu_hash_ = true; 685ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 686ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 687ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return gnu_hash_; 6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi, 6912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov soinfo** si_found_in, const soinfo::soinfo_list_t& global_group, 6922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) { 693ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov SymbolName symbol_name(name); 6942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 6956ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 69696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov /* "This element's presence in a shared object library alters the dynamic linker's 69796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * symbol resolution algorithm for references within the library. Instead of starting 69896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * a symbol search with the executable file, the dynamic linker starts from the shared 69996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * object itself. If the shared object fails to supply the referenced symbol, the 70096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * dynamic linker then searches the executable file and other shared objects as usual." 70196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * 70296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html 70396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * 70496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * Note that this is unlikely since static linker avoids generating 70596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * relocations for -Bsymbolic linked dynamic executables. 70696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov */ 707d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (si_from->has_DT_SYMBOLIC) { 708b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name); 7092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) { 7102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 7112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7138f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s != nullptr) { 714d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov *si_found_in = si_from; 71596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 71696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 71796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov 718d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // 1. Look for it in global_group 719d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (s == nullptr) { 7202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov bool error = false; 721d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov global_group.visit([&](soinfo* global_si) { 722aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s: looking up %s in %s (from global group)", 723b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov si_from->get_realpath(), name, global_si->get_realpath()); 7242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) { 7252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov error = true; 7262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 7272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 72996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (s != nullptr) { 730d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov *si_found_in = global_si; 731d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return false; 73296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 733c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 734d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return true; 735d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov }); 7362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (error) { 7382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 7392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 74096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 741c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 742d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // 2. Look for it in the local group 743cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (s == nullptr) { 7442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov bool error = false; 745cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov local_group.visit([&](soinfo* local_si) { 746d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (local_si == si_from && si_from->has_DT_SYMBOLIC) { 747e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov // we already did this - skip 748e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov return true; 749e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov } 750e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov 751aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s: looking up %s in %s (from local group)", 752b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov si_from->get_realpath(), name, local_si->get_realpath()); 7532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) { 7542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov error = true; 7552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 7562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 758cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (s != nullptr) { 759d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov *si_found_in = local_si; 760cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return false; 761cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 7626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 763cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 764cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 7652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (error) { 7672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 7682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 769cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 770cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 7716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s != nullptr) { 7726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " 7736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov "found in %s, base = %p, load bias = %p", 774b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value), 775b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base), 776d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov reinterpret_cast<void*>((*si_found_in)->load_bias)); 7776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 7786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 7792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol = s; 7802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 7816ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev} 7826ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 783279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovclass ProtectedDataGuard { 784279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov public: 785279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard() { 786279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov if (ref_count_++ == 0) { 787279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 788279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 789279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 790279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 791279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ~ProtectedDataGuard() { 792279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov if (ref_count_ == 0) { // overflow 793279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov __libc_fatal("Too many nested calls to dlopen()"); 794279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 795279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 796279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov if (--ref_count_ == 0) { 797279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov protect_data(PROT_READ); 798279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 799279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 800279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov private: 801279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov void protect_data(int protection) { 802279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov g_soinfo_allocator.protect_all(protection); 803279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov g_soinfo_links_allocator.protect_all(protection); 804279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 805279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 806279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov static size_t ref_count_; 807279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov}; 808279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 809279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovsize_t ProtectedDataGuard::ref_count_ = 0; 810279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 8110cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator. 8120cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 8130cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator { 8140cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 8150cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void* alloc() { 8160cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return allocator_.alloc(); 8170cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 8180cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 8190cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(void* ptr) { 8200cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov allocator_.free(ptr); 8210cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 8224bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov 8230cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private: 8240cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static LinkerBlockAllocator allocator_; 8250cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 8260cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 8270cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 8280cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size); 8290cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 8300cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T> 8310cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator { 8320cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 8330cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static T* alloc() { 8340cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc()); 8350cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 8360cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 8370cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(T* ptr) { 8380cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SizeBasedAllocator<sizeof(T)>::free(ptr); 8390cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 8400cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 8410cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 84214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask { 84314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public: 84414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct deleter_t { 84514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov void operator()(LoadTask* t) { 84614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TypeBasedAllocator<LoadTask>::free(t); 84714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 84814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }; 849a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 85014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov typedef UniquePtr<LoadTask, deleter_t> unique_ptr; 851d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom 85214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov static deleter_t deleter; 85314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 85414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov static LoadTask* create(const char* name, soinfo* needed_by) { 85514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc(); 85614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return new (ptr) LoadTask(name, needed_by); 857aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 858a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 85914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* get_name() const { 86014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return name_; 861a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 86214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 86314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* get_needed_by() const { 86414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return needed_by_; 86514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 86614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private: 86714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask(const char* name, soinfo* needed_by) 86814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov : name_(name), needed_by_(needed_by) {} 86914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 87014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name_; 87114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed_by_; 87214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 87314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); 874aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}; 875aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 876e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng JianLoadTask::deleter_t LoadTask::deleter; 877e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian 87814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T> 87914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>; 88014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 88114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList; 88214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList; 88314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<LoadTask> LoadTaskList; 88414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 88514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 886cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// This function walks down the tree of soinfo dependencies 887cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// in breadth-first order and 888cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// * calls action(soinfo* si) for each node, and 889cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// * terminates walk if action returns false. 890cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// 891cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// walk_dependencies_tree returns false if walk was terminated 892cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// by the action and true otherwise. 893cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovtemplate<typename F> 894cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovstatic bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) { 8950cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visit_list; 8960cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visited; 8970cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 898cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov for (size_t i = 0; i < root_soinfos_size; ++i) { 899cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov visit_list.push_back(root_soinfos[i]); 900cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 901cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 902cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfo* si; 903cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov while ((si = visit_list.pop_front()) != nullptr) { 904cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (visited.contains(si)) { 905042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov continue; 906042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov } 907042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov 908cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (!action(si)) { 909cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return false; 910aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 911aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 912cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov visited.push_back(si); 913cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 914cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov si->get_children().for_each([&](soinfo* child) { 915aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov visit_list.push_back(child); 916aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov }); 917aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 918aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 919cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 920cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov} 921cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 922cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 9234bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanovstatic const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until, 9244bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov soinfo** found, SymbolName& symbol_name) { 9252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* result = nullptr; 9264bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov bool skip_lookup = skip_until != nullptr; 9274bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov 9284bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) { 9294bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov if (skip_lookup) { 9304bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov skip_lookup = current_soinfo != skip_until; 9314bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov return true; 9324bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov } 933cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 9342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) { 9352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov result = nullptr; 9362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 9372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 9382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 939cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (result != nullptr) { 940cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov *found = current_soinfo; 941cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return false; 942cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 943cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 944cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 945cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 946cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 947cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return result; 9481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9504bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov// This is used by dlsym(3). It performs symbol lookup only within the 9514bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov// specified soinfo object and its dependencies in breadth first order. 9524bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanovconst ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { 953c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov // According to man dlopen(3) and posix docs in the case when si is handle 954c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov // of the main executable we need to search not only in the executable and its 955c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov // dependencies but also in all libraries loaded with RTLD_GLOBAL. 956c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov // 957c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared 958c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov // libraries and they are loaded in breath-first (correct) order we can just execute 959c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup. 960c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov if (si == somain) { 961c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT); 962c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov } 963c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov 9644bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov SymbolName symbol_name(name); 9654bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov return dlsym_handle_lookup(si, nullptr, found, symbol_name); 9664bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov} 9674bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov 968d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the 969d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom start value is null (for RTLD_DEFAULT), the search starts at the 970d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom beginning of the global solist. Otherwise the search starts at the 971d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom specified soinfo (for RTLD_NEXT). 9726ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */ 9732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst ElfW(Sym)* dlsym_linear_lookup(const char* name, 9742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov soinfo** found, 9752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov soinfo* caller, 9762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov void* handle) { 977ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov SymbolName symbol_name(name); 9781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 97976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov soinfo* start = solist; 98076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov 98176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov if (handle == RTLD_NEXT) { 98215309fde91b3989a1af139db422acf68e16a9258Dmitriy Ivanov if (caller == nullptr) { 98376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov return nullptr; 98476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov } else { 98576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov start = caller->next; 98676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov } 987cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 9881698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer 9892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 99076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov for (soinfo* si = start; si != nullptr; si = si->next) { 99104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...) 99204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // if the library is opened by application with target api level <= 22 99304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // See http://b/21565766 99404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) { 995e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov continue; 996e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 997e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 9982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) { 9992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return nullptr; 10002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 10012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 1002851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 1003cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes *found = si; 1004cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes break; 10051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1006cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 10071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 10084bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov // If not found - use dlsym_handle_lookup for caller's 10094bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov // local_group unless it is part of the global group in which 101076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov // case we already did it. 101176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov if (s == nullptr && caller != nullptr && 101276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) { 10134bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov return dlsym_handle_lookup(caller->get_local_group_root(), 10144bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name); 101576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov } 101676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov 1017851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 1018c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p", 1019c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base)); 1020cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 10211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1022cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes return s; 10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 10241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1025fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) { 10260266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p); 1027851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 1028fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (address >= si->base && address - si->base < si->size) { 1029fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return si; 1030e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 1031fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 1032851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1033e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 1034e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 1035ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) { 1036ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr); 1037ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 1038ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1039ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) { 1040ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return sym->st_shndx != SHN_UNDEF && 1041ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov soaddr >= sym->st_value && 1042ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov soaddr < sym->st_value + sym->st_size; 1043ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 1044ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1045ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) { 10468e5538193915885ea859ac90a72b46ab04440ceaChris Dearman ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias; 1047ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 10483597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov for (size_t i = 0; i < gnu_nbucket_; ++i) { 10493597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov uint32_t n = gnu_bucket_[i]; 1050ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1051ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (n == 0) { 1052ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov continue; 1053ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 1054ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1055ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov do { 1056047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* sym = symtab_ + n; 1057ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (symbol_matches_soaddr(sym, soaddr)) { 1058ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return sym; 1059ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 10603597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov } while ((gnu_chain_[n++] & 1) == 0); 1061ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 1062ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1063ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return nullptr; 1064ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 1065ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1066ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) { 10678e5538193915885ea859ac90a72b46ab04440ceaChris Dearman ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias; 1068fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 1069fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // Search the library's symbol table for any defined symbol which 1070fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // contains this address. 1071047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov for (size_t i = 0; i < nchain_; ++i) { 1072047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* sym = symtab_ + i; 1073ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (symbol_matches_soaddr(sym, soaddr)) { 1074fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return sym; 1075e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 1076fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 1077e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 1078851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1079e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 1080e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 1081aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwinstatic int open_library_in_zipfile(const char* const path, 1082aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin off64_t* file_offset) { 1083aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin TRACE("Trying zip file open from path '%s'", path); 1084aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1085524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov // Treat an '!/' separator inside a path as the separator between the name 1086aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // of the zip file on disk and the subdirectory to search within it. 1087524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov // For example, if path is "foo.zip!/bar/bas/x.so", then we search for 1088aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // "bar/bas/x.so" within "foo.zip". 1089524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov const char* separator = strstr(path, "!/"); 1090aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (separator == nullptr) { 1091aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1092aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1093aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1094aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin char buf[512]; 1095aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) { 1096aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin PRINT("Warning: ignoring very long library path: %s", path); 1097aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1098aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1099aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1100aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin buf[separator - path] = '\0'; 1101aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1102aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin const char* zip_path = buf; 1103524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov const char* file_path = &buf[separator - path + 2]; 1104aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); 1105aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd == -1) { 1106aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1107aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1108aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1109aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin ZipArchiveHandle handle; 1110aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (OpenArchiveFd(fd, "", &handle, false) != 0) { 1111aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // invalid zip-file (?) 1112aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin close(fd); 1113aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1114aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1115aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1116aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin auto archive_guard = make_scope_guard([&]() { 1117aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin CloseArchive(handle); 1118aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin }); 1119aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1120aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin ZipEntry entry; 1121aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1122aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (FindEntry(handle, ZipEntryName(file_path), &entry) != 0) { 1123aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // Entry was not found. 1124aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin close(fd); 1125aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1126aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1127aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1128aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // Check if it is properly stored 1129aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) { 1130aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin close(fd); 1131aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1132aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1133aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1134aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin *file_offset = entry.offset; 1135aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return fd; 1136aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin} 1137aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1138d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic bool format_path(char* buf, size_t buf_size, const char* path, const char* name) { 1139d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name); 1140d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (n < 0 || n >= static_cast<int>(buf_size)) { 1141d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov PRINT("Warning: ignoring very long library path: %s/%s", path, name); 1142d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return false; 1143d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1144d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 1145d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return true; 1146d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov} 1147aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1148d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic int open_library_on_default_path(const char* name, off64_t* file_offset) { 1149d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov for (size_t i = 0; kDefaultLdPaths[i] != nullptr; ++i) { 1150d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov char buf[512]; 1151aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (!format_path(buf, sizeof(buf), kDefaultLdPaths[i], name)) { 1152d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov continue; 1153d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1154d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 1155d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC)); 1156d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (fd != -1) { 1157d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov *file_offset = 0; 1158d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return fd; 11591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1160d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1161aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1162d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return -1; 1163d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov} 1164aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1165d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic int open_library_on_ld_library_path(const char* name, off64_t* file_offset) { 1166d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov for (const auto& path_str : g_ld_library_paths) { 1167d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov char buf[512]; 1168d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov const char* const path = path_str.c_str(); 1169d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (!format_path(buf, sizeof(buf), path, name)) { 1170d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov continue; 1171d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1172d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 1173d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov int fd = -1; 1174d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (strchr(buf, '!') != nullptr) { 1175aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin fd = open_library_in_zipfile(buf, file_offset); 1176aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1177aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1178aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd == -1) { 1179aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC)); 1180aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd != -1) { 1181aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin *file_offset = 0; 1182aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1183124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 1184d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 1185d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (fd != -1) { 1186d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return fd; 1187d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1188124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 1189aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1190d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return -1; 11911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 11921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1193aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwinstatic int open_library(const char* name, off64_t* file_offset) { 1194ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ opening %s ]", name); 11951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1196124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes // If the name contains a slash, we should attempt to open it directly and not search the paths. 1197851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (strchr(name, '/') != nullptr) { 1198aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (strchr(name, '!') != nullptr) { 1199aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin int fd = open_library_in_zipfile(name, file_offset); 1200aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd != -1) { 1201aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return fd; 1202aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1203aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1204aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 12056971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC)); 12066971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes if (fd != -1) { 1207aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin *file_offset = 0; 12086971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes } 1209e44fffd7f9b93b9ec9836cfc7acedf7e21107f8fDmitriy Ivanov return fd; 1210124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 12111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1212124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths. 1213d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov int fd = open_library_on_ld_library_path(name, file_offset); 1214124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (fd == -1) { 1215d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov fd = open_library_on_default_path(name, file_offset); 1216124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 1217124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return fd; 12181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 12191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 12204a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanovstatic const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) { 12214a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov#if !defined(__LP64__) 12224a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029 122304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if (get_application_target_sdk_version() <= 22) { 12244a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov const char* bname = basename(dt_needed); 12254a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov if (bname != dt_needed) { 12264a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed); 12274a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov } 12284a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov 12294a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov return bname; 12304a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov } 12314a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov#endif 12324a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov return dt_needed; 12334a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov} 12344a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov 123514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F> 123614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) { 123714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { 123814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (d->d_tag == DT_NEEDED) { 12394a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath())); 1240d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 124114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 124214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 1243d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 12442a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Lowstatic soinfo* load_library(int fd, off64_t file_offset, 12452a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low LoadTaskList& load_tasks, 1246aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin const char* name, int rtld_flags, 1247aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin const android_dlextinfo* extinfo) { 124807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((file_offset % PAGE_SIZE) != 0) { 1249a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset); 125007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 125107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 125216f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui if (file_offset < 0) { 125316f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset); 125416f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui return nullptr; 125516f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui } 125607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 125714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct stat file_stat; 125814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { 1259a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno)); 126014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 126114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 126216f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui if (file_offset >= file_stat.st_size) { 126320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64, 126420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov name, file_offset, file_stat.st_size); 126516f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui return nullptr; 126616f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui } 1267d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 126814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Check for symlink and other situations where 12699b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set 12709b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) { 12719b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 12729b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov if (si->get_st_dev() != 0 && 12739b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov si->get_st_ino() != 0 && 12749b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov si->get_st_dev() == file_stat.st_dev && 12759b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov si->get_st_ino() == file_stat.st_ino && 12769b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov si->get_file_offset() == file_offset) { 12779b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov TRACE("library \"%s\" is already loaded under different name/path \"%s\" - " 1278aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov "will return existing soinfo", name, si->get_realpath()); 12799b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov return si; 12809b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov } 1281498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov } 128214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1283d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1284e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if ((rtld_flags & RTLD_NOLOAD) != 0) { 1285a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); 128614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 128714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1288a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 1289aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov std::string realpath = name; 1290aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (!realpath_fd(fd, &realpath)) { 1291ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name); 1292aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov realpath = name; 1293aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 1294aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 129514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Read the ELF header and load the segments. 1296aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov ElfReader elf_reader(realpath.c_str(), fd, file_offset); 129714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!elf_reader.Load(extinfo)) { 129814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 129914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1300d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1301aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags); 130214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == nullptr) { 130314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 130414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 130514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->base = elf_reader.load_start(); 130614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->size = elf_reader.load_size(); 130714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->load_bias = elf_reader.load_bias(); 130814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->phnum = elf_reader.phdr_count(); 130914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->phdr = elf_reader.loaded_phdr(); 131014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1311047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!si->prelink_image()) { 131214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_free(si); 131314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 131414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1315a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 131614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for_each_dt_needed(si, [&] (const char* name) { 131714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.push_back(LoadTask::create(name, si)); 131814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 131914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 132014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 13211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 13221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 13232a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Lowstatic soinfo* load_library(LoadTaskList& load_tasks, 13242a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low const char* name, int rtld_flags, 13252a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low const android_dlextinfo* extinfo) { 13262a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { 13272a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low off64_t file_offset = 0; 13282a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) { 13292a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low file_offset = extinfo->library_fd_offset; 13302a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low } 13312a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo); 13322a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low } 13332a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low 13342a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low // Open the file. 13352a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low off64_t file_offset; 13362a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low int fd = open_library(name, &file_offset); 13372a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low if (fd == -1) { 13382a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low DL_ERR("library \"%s\" not found", name); 13392a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low return nullptr; 13402a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low } 13412a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo); 13422a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low close(fd); 13432a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low return result; 13442a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low} 13452a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low 134628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov// Returns true if library was found and false in 2 cases 134728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov// 1. The library was found but loaded under different target_sdk_version 134828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov// (*candidate != nullptr) 134928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov// 2. The library was not found by soname (*candidate is nullptr) 135028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanovstatic bool find_loaded_library_by_soname(const char* name, soinfo** candidate) { 135128154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov *candidate = nullptr; 135228154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov 1353618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // Ignore filename with path. 1354618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov if (strchr(name, '/') != nullptr) { 135528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov return false; 1356618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } 1357618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 135828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov uint32_t target_sdk_version = get_application_target_sdk_version(); 135928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov 1360851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 1361618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov const char* soname = si->get_soname(); 1362618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov if (soname != nullptr && (strcmp(name, soname) == 0)) { 136328154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // If the library was opened under different target sdk version 136428154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // skip this step and try to reopen it. The exceptions are 136528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // "libdl.so" and global group. There is no point in skipping 136628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // them because relocation process is going to use them 136728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // in any case. 136828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov bool is_libdl = si == solist; 136928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 || 137028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov !si->is_linked() || si->get_target_sdk_version() == target_sdk_version) { 137128154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov *candidate = si; 137228154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov return true; 137328154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov } else if (*candidate == nullptr) { 137428154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // for the different sdk version - remember the first library. 137528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov *candidate = si; 137628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov } 137712c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel } 1378489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov } 137928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov 138028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov return false; 138112c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel} 138212c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel 138320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, 138420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov int rtld_flags, const android_dlextinfo* extinfo) { 138528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov soinfo* candidate; 138628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov 138728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov if (find_loaded_library_by_soname(name, &candidate)) { 138828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov return candidate; 138928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov } 1390b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 1391b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // Library might still be loaded, the accurate detection 139214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // of this fact is done by load_library. 139328154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]", 139428154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate); 139528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov 139628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov soinfo* si = load_library(load_tasks, name, rtld_flags, extinfo); 139728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov 139828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // In case we were unable to load the library but there 139928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // is a candidate loaded under the same soname but different 140028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov // sdk level - return it anyways. 140128154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov if (si == nullptr && candidate != nullptr) { 140228154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov si = candidate; 1403b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov } 1404b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 140514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 140614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 140714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 140814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si); 140914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1410d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// TODO: this is slightly unusual way to construct 1411d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// the global group for relocation. Not every RTLD_GLOBAL 1412d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// library is included in this group for backwards-compatibility 1413d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// reasons. 1414d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// 1415d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// This group consists of the main executable, LD_PRELOADs 1416d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// and libraries with the DF_1_GLOBAL flag set. 1417d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovstatic soinfo::soinfo_list_t make_global_group() { 1418d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov soinfo::soinfo_list_t global_group; 1419d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov for (soinfo* si = somain; si != nullptr; si = si->next) { 1420d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) { 1421d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov global_group.push_back(si); 1422d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 1423d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 1424d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 1425d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return global_group; 1426d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 1427d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 1428d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic bool find_libraries(soinfo* start_with, const char* const library_names[], 1429d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov size_t library_names_count, soinfo* soinfos[], std::vector<soinfo*>* ld_preloads, 1430d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) { 143114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 0: prepare. 143214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTaskList load_tasks; 1433cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov for (size_t i = 0; i < library_names_count; ++i) { 143414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name = library_names[i]; 1435cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov load_tasks.push_back(LoadTask::create(name, start_with)); 1436cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 1437cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1438d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // Construct global_group. 1439d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov soinfo::soinfo_list_t global_group = make_global_group(); 1440d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 1441cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // If soinfos array is null allocate one on stack. 1442cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // The array is needed in case of failure; for example 1443cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // when library_names[] = {libone.so, libtwo.so} and libone.so 1444cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // is loaded correctly but libtwo.so failed for some reason. 1445cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // In this case libone.so should be unloaded on return. 1446cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // See also implementation of failure_guard below. 1447cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1448cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (soinfos == nullptr) { 1449cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov size_t soinfos_size = sizeof(soinfo*)*library_names_count; 1450cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size)); 1451cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov memset(soinfos, 0, soinfos_size); 145214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 145314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1454cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // list of libraries to link - see step 2. 1455cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov size_t soinfos_count = 0; 145614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1457d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov auto failure_guard = make_scope_guard([&]() { 145814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Housekeeping 145914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.for_each([] (LoadTask* t) { 146014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask::deleter(t); 146114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 146214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1463cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov for (size_t i = 0; i<soinfos_count; ++i) { 146414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_unload(soinfos[i]); 146514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 146614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 146714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 146814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order. 146920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov for (LoadTask::unique_ptr task(load_tasks.pop_front()); 147020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov task.get() != nullptr; task.reset(load_tasks.pop_front())) { 1471e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo); 147214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == nullptr) { 147314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 147414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 147514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 147614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed_by = task->get_needed_by(); 147714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 147814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (needed_by != nullptr) { 147914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov needed_by->add_child(si); 148014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 148114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1482ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (si->is_linked()) { 1483ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->increment_ref_count(); 1484ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 1485ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 1486cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // When ld_preloads is not null, the first 1487cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // ld_preloads_count libs are in fact ld_preloads. 1488cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { 1489d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // Add LD_PRELOADed libraries to the global group for future runs. 1490d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // There is no need to explicitly add them to the global group 1491d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // for this run because they are going to appear in the local 1492d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // group in the correct order. 1493d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); 1494d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov ld_preloads->push_back(si); 149514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 149614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1497cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (soinfos_count < library_names_count) { 1498cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfos[soinfos_count++] = si; 149914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 150014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 150114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 150214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 2: link libraries. 1503cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfo::soinfo_list_t local_group; 1504cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov walk_dependencies_tree( 1505cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov start_with == nullptr ? soinfos : &start_with, 1506cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov start_with == nullptr ? soinfos_count : 1, 1507cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov [&] (soinfo* si) { 1508cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov local_group.push_back(si); 1509cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 1510cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 1511cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1512ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // We need to increment ref_count in case 1513ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // the root of the local group was not linked. 1514ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov bool was_local_group_root_linked = local_group.front()->is_linked(); 1515ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 1516cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov bool linked = local_group.visit([&](soinfo* si) { 1517ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!si->is_linked()) { 1518047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!si->link_image(global_group, local_group, extinfo)) { 151914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 152014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1521ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->set_linked(); 152214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1523cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1524cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 1525cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 1526cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1527cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (linked) { 1528cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov failure_guard.disable(); 1529a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 153014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1531ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!was_local_group_root_linked) { 1532ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group.front()->increment_ref_count(); 1533ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 1534ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 1535cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return linked; 153614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 153714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1538e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { 153914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* si; 154014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1541ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (name == nullptr) { 1542ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si = somain; 1543ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { 154414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 154514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 154614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1547d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return si; 1548d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 1549d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1550ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovstatic void soinfo_unload(soinfo* root) { 1551ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // Note that the library can be loaded but not linked; 1552ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // in which case there is no root but we still need 1553ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // to walk the tree and unload soinfos involved. 1554ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // 1555ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // This happens on unsuccessful dlopen, when one of 1556ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // the DT_NEEDED libraries could not be linked/found. 1557ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (root->is_linked()) { 1558ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov root = root->get_local_group_root(); 15591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov } 15601b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov 1561ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!root->can_unload()) { 1562b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath()); 1563ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return; 1564ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 1565d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1566ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov size_t ref_count = root->is_linked() ? root->decrement_ref_count() : 0; 1567ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 1568ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (ref_count == 0) { 1569ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo::soinfo_list_t local_unload_list; 1570ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo::soinfo_list_t external_unload_list; 1571ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo::soinfo_list_t depth_first_list; 1572ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov depth_first_list.push_back(root); 1573ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo* si = nullptr; 1574ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 1575ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov while ((si = depth_first_list.pop_front()) != nullptr) { 15765ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov if (local_unload_list.contains(si)) { 15775ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov continue; 15785ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov } 15795ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov 1580ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_unload_list.push_back(si); 15815ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov 1582ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (si->has_min_version(0)) { 1583ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo* child = nullptr; 1584ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov while ((child = si->get_children().pop_front()) != nullptr) { 1585b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si, 1586b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov child->get_realpath(), child); 1587b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov 1588ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (local_unload_list.contains(child)) { 1589ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov continue; 15905ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov } else if (child->is_linked() && child->get_local_group_root() != root) { 1591ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov external_unload_list.push_back(child); 1592ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else { 1593ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov depth_first_list.push_front(child); 1594ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 1595d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1596ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else { 159769a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if !defined(__work_around_b_19059885__) 1598b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si); 15995ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#else 1600b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si); 1601ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov for_each_dt_needed(si, [&] (const char* library_name) { 1602aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov TRACE("deprecated (old format of soinfo): %s needs to unload %s", 1603b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov si->get_realpath(), library_name); 1604aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 1605ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); 1606ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (needed != nullptr) { 1607ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // Not found: for example if symlink was deleted between dlopen and dlclose 1608ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // Since we cannot really handle errors at this point - print and continue. 1609aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov PRINT("warning: couldn't find %s needed by %s on unload.", 1610b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov library_name, si->get_realpath()); 1611ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return; 1612ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else if (local_unload_list.contains(needed)) { 1613ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // already visited 1614ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return; 16155ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov } else if (needed->is_linked() && needed->get_local_group_root() != root) { 1616ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // external group 1617ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov external_unload_list.push_back(needed); 1618ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else { 1619ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // local group 1620ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov depth_first_list.push_front(needed); 1621ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 1622ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov }); 16235ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#endif 1624ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 16251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 16261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1627ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_unload_list.for_each([](soinfo* si) { 1628ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->call_destructors(); 1629ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov }); 16301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1631ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov while ((si = local_unload_list.pop_front()) != nullptr) { 1632ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov notify_gdb_of_unload(si); 1633ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo_free(si); 1634ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 1635a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov 1636ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov while ((si = external_unload_list.pop_front()) != nullptr) { 1637ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov soinfo_unload(si); 1638ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 1639ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else { 1640b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("not unloading '%s' group, decrementing ref_count to %zd", 1641b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov root->get_realpath(), ref_count); 1642a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov } 1643a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov} 1644a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov 1645a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) { 1646052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Use basic string manipulation calls to avoid snprintf. 1647052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf indirectly calls pthread_getspecific to get the size of a buffer. 1648052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // When debug malloc is enabled, this call returns 0. This in turn causes 1649052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf to do nothing, which causes libraries to fail to load. 1650052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // See b/17302493 for further details. 1651052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Once the above bug is fixed, this code can be modified to use 1652052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf again. 1653052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2; 1654052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris if (buffer_size < required_len) { 165520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: " 165620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov "buffer len %zu, required len %zu", buffer_size, required_len); 1657052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris } 1658052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris char* end = stpcpy(buffer, kDefaultLdPaths[0]); 1659052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris *end = ':'; 1660052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris strcpy(end + 1, kDefaultLdPaths[1]); 1661a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes} 1662a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 1663cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { 16646bb01b6e6365ced7ca23c9ebecfaf1ea159d5ae2Nick Kralevich parse_LD_LIBRARY_PATH(ld_library_path); 1665cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 1666cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 16671a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughessoinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { 16681b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) { 1669e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes DL_ERR("invalid flags to dlopen: %x", flags); 1670851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1671e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes } 167207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if (extinfo != nullptr) { 167307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) { 167407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags); 167507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 167607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 167707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 && 1678a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) { 167920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without " 168020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags); 168107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 168207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 1683012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles) } 1684279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 1685279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard guard; 16869fb216f844bb15c8e8f27c5ac0490a2f6faacb57Dmitriy Ivanov soinfo* si = find_library(name, flags, extinfo); 1687851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (si != nullptr) { 1688047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->call_constructors(); 1689d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1690d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return si; 1691d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1693b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid do_dlclose(soinfo* si) { 1694279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard guard; 1695b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov soinfo_unload(si); 16961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 16989aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { 16999aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov typedef ElfW(Addr) (*ifunc_resolver_t)(void); 17009aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr); 17019aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ElfW(Addr) ifunc_addr = ifunc_resolver(); 170220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", 170320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ifunc_resolver, reinterpret_cast<void*>(ifunc_addr)); 1704c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 17059aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return ifunc_addr; 1706c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith} 1707c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 17082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const { 17092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (source_symver < 2 || 17102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov source_symver >= version_infos.size() || 17112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_symver].name == nullptr) { 17122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return nullptr; 17132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return &version_infos[source_symver]; 17162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 17172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovvoid VersionTracker::add_version_info(size_t source_index, 17192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Word) elf_hash, 17202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const char* ver_name, 17212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const soinfo* target_si) { 17222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (source_index >= version_infos.size()) { 17232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos.resize(source_index+1); 17242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_index].elf_hash = elf_hash; 17272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_index].name = ver_name; 17282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_index].target_si = target_si; 17292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 17302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verneed(const soinfo* si_from) { 17322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uintptr_t verneed_ptr = si_from->get_verneed_ptr(); 17332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed_ptr == 0) { 17352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 17362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t verneed_cnt = si_from->get_verneed_cnt(); 17392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) { 17412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset); 17422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t vernaux_offset = offset + verneed->vn_aux; 17432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov offset += verneed->vn_next; 17442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed->vn_version != 1) { 17462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version); 17472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 17482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const char* target_soname = si_from->get_string(verneed->vn_file); 17512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // find it in dependencies 17522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) { 17538264afb37778bea2a3c6e9aa7144f4877401c3f8Dmitriy Ivanov return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0; 17542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov }); 17552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (target_si == nullptr) { 17572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"", 1758b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov target_soname, i, si_from->get_realpath()); 17592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 17602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov for (size_t j = 0; j<verneed->vn_cnt; ++j) { 17632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset); 17642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov vernaux_offset += vernaux->vna_next; 17652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Word) elf_hash = vernaux->vna_hash; 17672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const char* ver_name = si_from->get_string(vernaux->vna_name); 17682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Half) source_index = vernaux->vna_other; 17692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov add_version_info(source_index, elf_hash, ver_name, target_si); 17712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 17752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 17762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verdef(const soinfo* si_from) { 17782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return for_each_verdef(si_from, 17792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) { 17802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov add_version_info(verdef->vd_ndx, verdef->vd_hash, 17812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov si_from->get_string(verdaux->vda_name), si_from); 17822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 17832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ); 17852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 17862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init(const soinfo* si_from) { 17882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!si_from->has_min_version(2)) { 17892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 17902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 17912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 17922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return init_verneed(si_from) && init_verdef(si_from); 17932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 17942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 1795114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanovbool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym, 1796114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov const char* sym_name, const version_info** vi) { 1797114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov const ElfW(Versym)* sym_ver_ptr = get_versym(sym); 1798114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr; 1799114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov 1800114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) { 1801114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov *vi = version_tracker.get_version_info(sym_ver); 1802114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov 1803114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov if (*vi == nullptr) { 1804114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov DL_ERR("cannot find verneed/verdef for version index=%d " 1805b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath()); 1806114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov return false; 1807114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov } 1808114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov } else { 1809114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov // there is no version info 1810114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov *vi = nullptr; 1811114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov } 1812114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov 1813114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov return true; 1814114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov} 1815114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov 1816bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#if !defined(__mips__) 18174eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 1818bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) { 1819bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov return rela->r_addend; 1820bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov} 1821bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#else 1822bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) { 182320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE || 182420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) { 1825bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov return *reinterpret_cast<ElfW(Addr)*>(reloc_addr); 1826bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov } 1827bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov return 0; 1828bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov} 1829bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif 1830bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov 1831fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanovtemplate<typename ElfRelIteratorT> 1832f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanovbool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator, 1833f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov const soinfo_list_t& global_group, const soinfo_list_t& local_group) { 1834fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov for (size_t idx = 0; rel_iterator.has_next(); ++idx) { 1835fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov const auto rel = rel_iterator.next(); 183618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (rel == nullptr) { 183718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 183818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 183918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 1840bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Word) type = ELFW(R_TYPE)(rel->r_info); 1841bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Word) sym = ELFW(R_SYM)(rel->r_info); 1842bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov 1843bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias); 18440266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) sym_addr = 0; 1845851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov const char* sym_name = nullptr; 1846bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Addr) addend = get_addend(rel, reloc); 1847c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1848b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx); 1849cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov if (type == R_GENERIC_NONE) { 1850c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes continue; 1851c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 185214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 18532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 185414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* lsi = nullptr; 185514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1856c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (sym != 0) { 1857047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov sym_name = get_string(symtab_[sym].st_name); 1858114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov const version_info* vi = nullptr; 18592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 1860114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { 1861114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov return false; 1862114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov } 18632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 1864114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { 1865114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov return false; 18662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 1867114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov 1868851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s == nullptr) { 1869c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes // We only allow an undefined symbol if this is a weak reference... 1870047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov s = &symtab_[sym]; 1871c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 1872b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath()); 1873114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 1874c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1875c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1876c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes /* IHI0044C AAELF 4.5.1.1: 1877c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1878c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes Libraries are not searched to resolve weak references. 1879c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes It is not an error for a weak reference to remain unsatisfied. 1880c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1881c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes During linking, the value of an undefined weak reference is: 1882c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - Zero if the relocation type is absolute 1883c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of the place if the relocation is pc-relative 1884c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of nominal base address if the relocation 1885c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes type is base-relative. 1886c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes */ 1887c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1888c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 18891b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_JUMP_SLOT: 18901b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_GLOB_DAT: 18911b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_RELATIVE: 18921b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_IRELATIVE: 1893e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__) 18946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 18956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 18966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 18971b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#elif defined(__x86_64__) 18981b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_X86_64_32: 18991b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_X86_64_64: 1900bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__) 1901bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov case R_ARM_ABS32: 1902bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__) 1903bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov case R_386_32: 19041b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#endif 19056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 19066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * The sym_addr was initialized to be zero above, or the relocation 19076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * code below does not care about value of sym_addr. 19086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * No need to do anything. 19096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 19106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19111b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#if defined(__x86_64__) 1912d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov case R_X86_64_PC32: 1913d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov sym_addr = reloc; 1914d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov break; 1915bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__) 1916bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov case R_386_PC32: 1917bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov sym_addr = reloc; 1918bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov break; 1919bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif 19206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 1921bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx); 1922114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 1923c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1924c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } else { 1925c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes // We got a definition. 19269aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 1927c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1928c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes count_relocation(kRelocSymbol); 1929c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1930c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1931c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 1932cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_JUMP_SLOT: 1933e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1934bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1935bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n", 1936bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 1937bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(sym_addr + addend), sym_name); 1938bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov 1939bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend); 1940e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1941cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_GLOB_DAT: 1942e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1943bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1944bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n", 1945bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 1946bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(sym_addr + addend), sym_name); 1947bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend); 1948e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1949cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_RELATIVE: 1950cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov count_relocation(kRelocRelative); 1951bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1952bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n", 1953bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 195418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reinterpret_cast<void*>(load_bias + addend)); 195518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend); 1956cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov break; 1957cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_IRELATIVE: 1958cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov count_relocation(kRelocRelative); 1959bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1960bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n", 1961bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 196218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reinterpret_cast<void*>(load_bias + addend)); 196318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend); 1964cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov break; 1965cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov 1966cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__aarch64__) 19676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 1968e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1969bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 19700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n", 1971bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), sym_name); 1972bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend); 1973e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 19746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 1975e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1976bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 19770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS32 %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)>(INT32_MIN); 198220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_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_ABS16: 1994e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1995bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 19960266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n", 1997bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), sym_name); 199820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 199920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc); 200020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); 200120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX); 200220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if ((min_value <= (reloc_value + (sym_addr + addend))) && 200320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ((reloc_value + (sym_addr + addend)) <= max_value)) { 200420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend); 200520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 200620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 200720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reloc_value + (sym_addr + addend), min_value, max_value); 200820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 200920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2010e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2011e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL64: 2013e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2014bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20150266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n", 2016bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset, sym_name); 2017bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset; 2018e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL32: 2020e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2021bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL32 %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)>(INT32_MIN); 202720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_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; 20386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL16: 2039e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2040bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20410266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n", 2042bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset, sym_name); 204320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 204420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc); 204520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); 204620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX); 204720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) && 204820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) { 204920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset); 205020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 205120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 205220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value); 205320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 205420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2055e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2056e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 2057e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 20586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_COPY: 205976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich /* 206076e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * ET_EXEC is not supported so this should not happen. 206176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 2062aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf 206376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 2064aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * Section 4.6.11 "Dynamic relocations" 206576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * R_AARCH64_COPY may only appear in executable objects where e_type is 206676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * set to ET_EXEC. 206776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich */ 2068b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath()); 2069114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 20706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_TPREL64: 20710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", 2072bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset); 2073e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_DTPREL32: 20750266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n", 2076bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset); 2077e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 2078e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__) 20796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_32: 20806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 2081bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 20836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 2084bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; 20856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_64: 20876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 2088bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 20906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 2091bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; 20926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_PC32: 20946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 2095bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", 20976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc), 20986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name); 2099bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc; 21006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2101bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__) 21026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_ABS32: 21036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 21046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name); 21066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 21076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_REL32: 21096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 21106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s", 21126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, sym_addr, rel->r_offset, sym_name); 21136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset; 21146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_COPY: 21166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 21176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * ET_EXEC is not supported so this should not happen. 21186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 21196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 21206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 2121aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * Section 4.6.1.10 "Dynamic relocations" 21226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * R_ARM_COPY may only appear in executable objects where e_type is 21236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * set to ET_EXEC. 21246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 2125b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath()); 2126114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 21274eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 21286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_32: 21296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 21306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); 21326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 21336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_PC32: 21356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 21366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", 21386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); 21396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc); 21406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21414eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 21426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 21436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); 21446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2145d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 21466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 2148d7daacb46372132ae3f0121647074936c304b572Raghu Gandham} 2149114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#endif // !defined(__mips__) 2150d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 215120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid soinfo::call_array(const char* array_name __unused, linker_function_t* functions, 215220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov size_t count, bool reverse) { 2153851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (functions == nullptr) { 2154d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 2155d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 21568215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2157b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath()); 21588215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2159ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int begin = reverse ? (count - 1) : 0; 2160ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int end = reverse ? -1 : count; 2161ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int step = reverse ? -1 : 1; 21628215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2163ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes for (int i = begin; i != end; i += step) { 2164ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]); 2165047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("function", functions[i]); 2166d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 2167d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2168b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath()); 21691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 21701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2171047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_function(const char* function_name __unused, linker_function_t function) { 2172851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) { 2173d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 2174d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 2175d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2176b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath()); 2177d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes function(); 2178b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath()); 21799181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov} 21809181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 2181047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_pre_init_constructors() { 21828147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_PREINIT_ARRAY functions are called before any other constructors for executables, 21838147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // but ignored in a shared library. 2184047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false); 2185d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 2186e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 2187047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_constructors() { 2188d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes if (constructors_called) { 2189d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 2190d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 2191e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 2192d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // We set constructors_called before actually calling the constructors, otherwise it doesn't 2193d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // protect against recursive constructor calls. One simple example of constructor recursion 2194d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so: 2195d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 1. The program depends on libc, so libc's constructor is called here. 2196d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so. 2197d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 3. dlopen() calls the constructors on the newly created 2198d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // soinfo for libc_malloc_debug_leak.so. 2199d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 4. The debug .so depends on libc, so CallConstructors is 2200d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // called again with the libc soinfo. If it doesn't trigger the early- 2201d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // out above, the libc constructor will be called again (recursively!). 2202d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes constructors_called = true; 2203d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2204ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!is_main_executable() && preinit_array_ != nullptr) { 22058147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // The GNU dynamic linker silently ignores these, but we warn the developer. 2206c620059479c47a78d57086d73726c9adc2f337adElliott Hughes PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!", 2207b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), preinit_array_count_); 2208d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 22091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2210d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov get_children().for_each([] (soinfo* si) { 2211047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->call_constructors(); 2212d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 22131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2214b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("\"%s\": calling constructors", get_realpath()); 22158147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 22168147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_INIT should be called before DT_INIT_ARRAY if both are present. 2217047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("DT_INIT", init_func_); 2218047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false); 2219e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov} 22208215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2221047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_destructors() { 222214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!constructors_called) { 222314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return; 222414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 2225b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("\"%s\": calling destructors", get_realpath()); 22268147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 22278147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI_ARRAY must be parsed in reverse order. 2228047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true); 22298147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 22308147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI should be called after DT_FINI_ARRAY if both are present. 2231047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("DT_FINI", fini_func_); 2232b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 2233b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // This is needed on second call to dlopen 2234b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // after library has been unloaded with RTLD_NODELETE 2235b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov constructors_called = false; 22361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 22371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2238d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) { 22390d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2240047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov child->parents_.push_back(this); 2241047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->children_.push_back(child); 2242d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2243d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2244d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2245d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() { 22460d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (!has_min_version(0)) { 2247d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return; 2248d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2249d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2250d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 1. Untie connected soinfos from 'this'. 2251047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov children_.for_each([&] (soinfo* child) { 2252047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov child->parents_.remove_if([&] (const soinfo* parent) { 2253d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return parent == this; 2254d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2255d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2256d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2257047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parents_.for_each([&] (soinfo* parent) { 2258047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parent->children_.remove_if([&] (const soinfo* child) { 2259d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return child == this; 2260d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2261d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2262d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2263d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 2. Once everything untied - clear local lists. 2264047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parents_.clear(); 2265047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov children_.clear(); 2266d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2267d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2268d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovdev_t soinfo::get_st_dev() const { 22690d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2270047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return st_dev_; 2271d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2272d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 22730d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 2274d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}; 2275d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2276d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovino_t soinfo::get_st_ino() const { 22770d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2278047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return st_ino_; 2279d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2280d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 22810d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 2282d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2283d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2284d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovoff64_t soinfo::get_file_offset() const { 228507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if (has_min_version(1)) { 2286047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return file_offset_; 228707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 228807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 228907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return 0; 229007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov} 229107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 2292d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_rtld_flags() const { 2293e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (has_min_version(1)) { 2294047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return rtld_flags_; 2295e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 2296e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 2297e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov return 0; 2298e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov} 2299e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 2300d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_dt_flags_1() const { 2301d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (has_min_version(1)) { 2302047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return dt_flags_1_; 2303d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2304d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2305d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return 0; 2306d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 2307618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 2308d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovvoid soinfo::set_dt_flags_1(uint32_t dt_flags_1) { 2309d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (has_min_version(1)) { 2310d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((dt_flags_1 & DF_1_GLOBAL) != 0) { 2311047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rtld_flags_ |= RTLD_GLOBAL; 2312d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2313d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2314d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((dt_flags_1 & DF_1_NODELETE) != 0) { 2315047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rtld_flags_ |= RTLD_NODELETE; 2316d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2317d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2318047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov dt_flags_1_ = dt_flags_1; 2319d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2320d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 2321d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2322aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_realpath() const { 232369a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__) 2324aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (has_min_version(2)) { 2325aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return realpath_.c_str(); 2326aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } else { 2327aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return old_name_; 2328aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 2329aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else 2330aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return realpath_.c_str(); 2331aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif 2332aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov} 2333aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 2334aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_soname() const { 233569a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__) 2336618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov if (has_min_version(2)) { 2337618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov return soname_; 2338618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } else { 2339aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return old_name_; 2340618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } 2341aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else 2342aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return soname_; 2343aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif 2344618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov} 2345618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 234614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if 2347d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set. 2348d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list; 2349d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2350d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() { 23510d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2352047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return children_; 2353d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2354d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 23550d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return g_empty_list; 2356d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2357d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 23582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst soinfo::soinfo_list_t& soinfo::get_children() const { 23592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(0)) { 23602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return children_; 23612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 23622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 23632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return g_empty_list; 23642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 23652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 236614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() { 2367047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (has_min_version(0)) { 2368047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return parents_; 236914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 237014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2371047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return g_empty_list; 237214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 237314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 23742a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const { 23759aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { 23769aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return call_ifunc_resolver(s->st_value + load_bias); 23779aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov } 23789aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 23799aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return static_cast<ElfW(Addr)>(s->st_value + load_bias); 23809aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov} 23819aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 23826cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const { 2383047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (has_min_version(1) && (index >= strtab_size_)) { 2384aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", 2385b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strtab_size_, index); 23866cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 23876cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 2388047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return strtab_ + index; 23896cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov} 23906cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 2391ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovbool soinfo::is_gnu_hash() const { 2392ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_GNU_HASH) != 0; 2393ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 2394ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 23951b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const { 2396d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; 23971b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov} 2398d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2399ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_linked() const { 2400ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_LINKED) != 0; 2401ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2402ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2403ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_main_executable() const { 2404ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_EXE) != 0; 2405ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2406ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2407ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linked() { 2408ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_LINKED; 2409ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2410ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2411ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linker_flag() { 2412ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_LINKER; 2413ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2414ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2415ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_main_executable() { 2416ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_EXE; 2417ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2418ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2419ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::increment_ref_count() { 2420ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_->ref_count_++; 2421ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2422ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2423ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsize_t soinfo::decrement_ref_count() { 2424ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return --local_group_root_->ref_count_; 2425ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2426ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2427ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsoinfo* soinfo::get_local_group_root() const { 2428ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return local_group_root_; 2429ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2430ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 243104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// This function returns api-level at the time of 243204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// dlopen/load. Note that libraries opened by system 243304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// will always have 'current' api level. 243404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanovuint32_t soinfo::get_target_sdk_version() const { 243504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if (!has_min_version(2)) { 243604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov return __ANDROID_API__; 243704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov } 243804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov 243904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov return local_group_root_->target_sdk_version_; 244004f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov} 244104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov 2442047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::prelink_image() { 2443e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian /* Extract dynamic section */ 2444e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian ElfW(Word) dynamic_flags = 0; 2445e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags); 2446498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov 24476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can't log anything until the linker is relocated */ 2448ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov bool relocating_linker = (flags_ & FLAG_LINKER) != 0; 24496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 245053ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov INFO("[ linking %s ]", get_realpath()); 2451ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_); 24526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 24536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 24546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dynamic == nullptr) { 2455b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner if (!relocating_linker) { 2456b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath()); 2457b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner } 24586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 24596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 24606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 24616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("dynamic = %p", dynamic); 246263f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner } 24636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 246463f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 24654eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 24666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, 24676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov &ARM_exidx, &ARM_exidx_count); 246863f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif 246963f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 24706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract useful information from dynamic section. 2471618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // Note that: "Except for the DT_NULL element at the end of the array, 2472618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // and the relative order of DT_NEEDED elements, entries may appear in any order." 2473618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // 2474618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html 24756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov uint32_t needed_count = 0; 24766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 24776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", 24786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 24796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (d->d_tag) { 24804a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SONAME: 2481618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // this is parsed after we have strtab initialized (see below). 24824a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2483ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 24846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_HASH: 2485047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 2486047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 2487047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8); 2488047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4); 24896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2490ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2491ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov case DT_GNU_HASH: 24923597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 2493ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // skip symndx 2494047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2]; 2495047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3]; 2496ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2497047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16); 24983597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_); 2499ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // amend chain for symndx = header[1] 250020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov gnu_chain_ = gnu_bucket_ + gnu_nbucket_ - 250120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 2502ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2503047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!powerof2(gnu_maskwords_)) { 250420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two", 2505aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov gnu_maskwords_, get_realpath()); 2506ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return false; 2507ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 2508047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov --gnu_maskwords_; 2509ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2510ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_GNU_HASH; 2511ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov break; 2512ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 25136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_STRTAB: 2514047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr); 25156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2516ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25176cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_STRSZ: 2518047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov strtab_size_ = d->d_un.d_val; 25196cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 2520ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMTAB: 2522047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr); 25236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2524ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25254a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SYMENT: 25264a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Sym))) { 2527aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("invalid DT_SYMENT: %zd in \"%s\"", 2528aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov static_cast<size_t>(d->d_un.d_val), get_realpath()); 25294a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 25304a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 25314a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2532ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTREL: 2534513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA) 2535513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov if (d->d_un.d_val != DT_RELA) { 2536aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath()); 2537513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov return false; 2538513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov } 2539513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else 25406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val != DT_REL) { 2541aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath()); 25426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 25436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2544c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 2545513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 2546ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_JMPREL: 25484eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 2549047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 2550c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 2551047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 2552c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 25536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2554ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTRELSZ: 25564eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 2557047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela)); 2558c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 2559047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel)); 2560c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 25616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2562ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTGOT: 25644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__) 25656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Used by mips and mips64. 2566047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr); 2567c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 25684a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // Ignore for other platforms... (because RTLD_LAZY is not supported) 25694a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2570ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_DEBUG: 25726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_DEBUG entry to the address of _r_debug for GDB 25736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // if the dynamic table is writable 25749918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64 25759918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree. 257614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as 25779918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable. 25789918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__)) 25796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((dynamic_flags & PF_W) != 0) { 25806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug); 25816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 25829918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif 2583c6292ea39cce054175e4f9f797c05aeb8da0ac4bDmitriy Ivanov break; 25844eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 25856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 2586047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 25876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2588ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELASZ: 2590047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela)); 25916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2592ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 259318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELA: 259418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr); 259518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 259618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 259718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELASZ: 259818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_size_ = d->d_un.d_val; 259918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 260018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 260118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_REL: 2602aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath()); 260318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 260418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 260518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELSZ: 2606aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath()); 260718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 260818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 26094a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELAENT: 26104a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rela))) { 2611f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val)); 26124a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 26134a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 26144a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2615ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2616ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // ignored (see DT_RELCOUNT comments for details) 26174a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELACOUNT: 26184a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2619ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 2621aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_REL in \"%s\"", get_realpath()); 26226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2623ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 2625aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath()); 26266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 262718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 2628c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 26296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 2630047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 26316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2632ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 2634047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel)); 26356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2636ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26374a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELENT: 26384a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rel))) { 2639f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val)); 26404a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 26414a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 26424a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2643ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 264418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_REL: 264518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr); 264618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 264718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 264818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELSZ: 264918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_size_ = d->d_un.d_val; 265018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 265118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 265218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELA: 2653aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath()); 265418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 265518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 265618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELASZ: 2657aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath()); 265818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 265918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 2660ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // "Indicates that all RELATIVE relocations have been concatenated together, 2661ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // and specifies the RELATIVE relocation count." 2662ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // 2663ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // TODO: Spec also mentions that this can be used to optimize relocation process; 2664ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Not currently used by bionic linker - ignored. 26654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELCOUNT: 26664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 266718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 26686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 2669aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath()); 26706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 267118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 267218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_RELASZ: 2673aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath()); 267418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 267518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 2676c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 26776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT: 2678047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 2679aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_); 26806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2681ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI: 2683047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 2684aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_); 26856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2686ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAY: 2688047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 2689aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_); 26906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2691ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAYSZ: 26931649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 26946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2695ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAY: 2697047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 2698aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_); 26996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2700ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAYSZ: 27021649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 27036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2704ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAY: 2706047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 2707aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_); 27086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2709ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAYSZ: 27111649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 27126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2713ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_TEXTREL: 271556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__) 2716aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath()); 27176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 271856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else 271956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov has_text_relocations = true; 272056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov break; 272156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 2722ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMBOLIC: 272496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 27256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2726ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_NEEDED: 27286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_count; 27296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2730ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FLAGS: 27326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val & DF_TEXTREL) { 273356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__) 2734aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath()); 27356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 273656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else 273756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov has_text_relocations = true; 273856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 27396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 274096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (d->d_un.d_val & DF_SYMBOLIC) { 274196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 274296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 27436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2744ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27456cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_FLAGS_1: 2746d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov set_dt_flags_1(d->d_un.d_val); 27476cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 2748d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) { 2749ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val)); 27506cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 27516cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 27524eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 27536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_MAP: 27546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. 27556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 27566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr); 27576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *dp = &_r_debug; 27586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 27596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2760688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham case DT_MIPS_RLD_MAP2: 2761688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB. 2762688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham { 276320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>( 276420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val); 2765688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham *dp = &_r_debug; 2766688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham } 2767688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham break; 2768ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_VERSION: 27706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_FLAGS: 27716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_BASE_ADDRESS: 27726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_UNREFEXTNO: 27736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2774d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 27756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_SYMTABNO: 2776047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_symtabno_ = d->d_un.d_val; 27776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2778d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 27796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_LOCAL_GOTNO: 2780047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_local_gotno_ = d->d_un.d_val; 27816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2782d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 27836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_GOTSYM: 2784047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_gotsym_ = d->d_un.d_val; 27856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 27864eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 2787ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Ignored: "Its use has been superseded by the DF_BIND_NOW flag" 2788ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov case DT_BIND_NOW: 2789ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov break; 2790ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2791513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERSYM: 27922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr); 27932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 27942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 2795513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEF: 27962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef_ptr_ = load_bias + d->d_un.d_ptr; 27972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 2798513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEFNUM: 27992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef_cnt_ = d->d_un.d_val; 28002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 28012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 2802e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko case DT_VERNEED: 28032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed_ptr_ = load_bias + d->d_un.d_ptr; 28042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 28052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 2806e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko case DT_VERNEEDNUM: 28072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed_cnt_ = d->d_un.d_val; 2808513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 2809d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 28106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 28118f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (!relocating_linker) { 2812aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(), 28138f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 28148f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 28156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 28161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 28176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 28181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 28196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", 2820047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov reinterpret_cast<void*>(base), strtab_, symtab_); 28211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 28226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Sanity checks. 28236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (relocating_linker && needed_count != 0) { 28246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); 28256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 28273597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov if (nbucket_ == 0 && gnu_nbucket_ == 0) { 2828aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" " 2829b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov "(new hash type from the future?)", get_realpath()); 28306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2832047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (strtab_ == 0) { 2833b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath()); 28346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2836047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (symtab_ == 0) { 2837b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath()); 28386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 284038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov 284107f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov // second pass - parse entries relying on strtab 284207f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 284307f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov if (d->d_tag == DT_SONAME) { 284407f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov soname_ = get_string(d->d_un.d_val); 284507f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#if defined(__work_around_b_19059885__) 284607f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov strlcpy(old_name_, soname_, sizeof(old_name_)); 284707f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#endif 284807f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov break; 284907f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov } 285007f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov } 285107f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov 285238c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov // Before M release linker was using basename in place of soname. 285304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // In the case when dt_soname is absent some apps stop working 285438c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov // because they can't find dt_needed library by soname. 285538c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov // This workaround should keep them working. (applies only 285604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // for apps targeting sdk version <=22). Make an exception for 285704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // the main executable and linker; they do not need to have dt_soname 285804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 && 285904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov get_application_target_sdk_version() <= 22) { 286038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov soname_ = basename(realpath_.c_str()); 286138c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"", 286238c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov get_realpath(), soname_); 286338c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov } 28646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 286514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 28661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 286718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovbool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group, 286818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const android_dlextinfo* extinfo) { 28691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2870ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_ = local_group.front(); 2871ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (local_group_root_ == nullptr) { 2872ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_ = this; 2873ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 2874ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 287504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) { 287604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov target_sdk_version_ = get_application_target_sdk_version(); 287704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov } 287804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov 2879f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov VersionTracker version_tracker; 2880f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov 2881f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!version_tracker.init(this)) { 2882f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov return false; 2883f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov } 2884f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov 288556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__) 288656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (has_text_relocations) { 288756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // Make segments writable to allow text relocations to work properly. We will later call 288856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // phdr_table_protect_segments() after all of them are applied and all constructors are run. 288956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_WARN("%s has text relocations. This is wasting memory and prevents " 2890b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov "security hardening. Please fix.", get_realpath()); 289156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 289256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 2893b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 289456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov return false; 289556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 289656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 289756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 289856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov 289918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (android_relocs_ != nullptr) { 290018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov // check signature 290118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (android_relocs_size_ > 3 && 290218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[0] == 'A' && 290318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[1] == 'P' && 290418870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov android_relocs_[2] == 'S' && 290518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[3] == '2') { 2906b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ android relocating %s ]", get_realpath()); 290718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 290818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov bool relocated = false; 290918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const uint8_t* packed_relocs = android_relocs_ + 4; 291018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const size_t packed_relocs_size = android_relocs_size_ - 4; 291118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 291218870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov relocated = relocate( 2913f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov version_tracker, 291418870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov packed_reloc_iterator<sleb128_decoder>( 291518870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov sleb128_decoder(packed_relocs, packed_relocs_size)), 291618870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov global_group, local_group); 291718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 291818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (!relocated) { 291918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 292018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 292118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } else { 292218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov DL_ERR("bad android relocation header."); 292318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 292418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 292518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 292618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 29274eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 2928047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (rela_ != nullptr) { 2929b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s ]", get_realpath()); 2930f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 2931f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) { 29326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2933c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 29346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2935047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (plt_rela_ != nullptr) { 2936b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s plt ]", get_realpath()); 2937f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 2938f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) { 29396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 29401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 29416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 29429aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else 2943047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (rel_ != nullptr) { 2944b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s ]", get_realpath()); 2945f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 2946f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) { 29476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 29481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 29496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2950047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (plt_rel_ != nullptr) { 2951b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s plt ]", get_realpath()); 2952f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 2953f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) { 29546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2955c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith } 29566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 29579aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif 2958c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 29594eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 2960dc145b510640202a60b0dfaef9d56cd8fc1c05a9Dmitriy Ivanov if (!mips_relocate_got(version_tracker, global_group, local_group)) { 29616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 29626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2963d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif 2964d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 2965b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ finished linking %s ]", get_realpath()); 29661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 296756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__) 296856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (has_text_relocations) { 296956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // All relocations are done, we can protect our segments back to read-only. 297056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 297156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_ERR("can't protect segments for \"%s\": %s", 2972b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 297356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov return false; 297456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 297556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 297656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 297756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov 29786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can also turn on GNU RELRO protection */ 29796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { 29806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", 2981b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 29826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 29836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 29849ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich 29856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Handle serializing/sharing the RELRO segment */ 29866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { 29876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, 29886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 29896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", 2990b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 29916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2992183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) } 29936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { 29946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, 29956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 29966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", 2997b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 29986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 29996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 30006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3001183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) 30026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov notify_gdb_of_load(this); 30036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 30041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 30051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3006468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 3007c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list. 3008c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers. 3009c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc. 3010c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */ 3011812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) { 30124eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR) 30130266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR)); 3014851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (ehdr_vdso == nullptr) { 30150266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return; 30160266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 3017c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 301807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0); 3019ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 30200266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff); 30210266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phnum = ehdr_vdso->e_phnum; 30220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso); 30230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->size = phdr_table_get_load_size(si->phdr, si->phnum); 30240266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->load_bias = get_elf_exec_load_bias(ehdr_vdso); 3025ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 3026047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->prelink_image(); 3027047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr); 3028c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif 3029c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov} 3030c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 3031c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/* 3032d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below. 3033d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 30340d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__) 30350d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64" 30360d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else 30370d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker" 30380d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif 3039aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 3040aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// This is done to avoid calling c-tor prematurely 3041aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// because soinfo c-tor needs memory allocator 3042aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// which might be initialized after global variables. 3043aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic uint8_t linker_soinfo_for_gdb_buf[sizeof(soinfo)] __attribute__((aligned(8))); 3044aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic soinfo* linker_soinfo_for_gdb = nullptr; 3045d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3046d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list. 3047d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text" 3048d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to 3049d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol. 3050d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't 3051d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list. 3052d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 3053d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) { 3054aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0); 3055aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 305638263dd91a4b68e2ad0afe458c9a20cb360dafebDmitriy Ivanov linker_soinfo_for_gdb->load_bias = linker_base; 3057d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3058d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov /* 3059d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Set the dynamic field in the link map otherwise gdb will complain with 3060d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * the following: 3061d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * warning: .dynamic section for "/system/bin/linker" is not at the 3062d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * expected address (wrong library or version mismatch?) 3063d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 3064d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base); 3065d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff); 3066d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, 3067aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov &linker_soinfo_for_gdb->dynamic, nullptr); 3068aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov insert_soinfo_into_debug_map(linker_soinfo_for_gdb); 3069d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 3070d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 30710b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanovextern "C" int __system_properties_init(void); 30720b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov 3073d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* 3074468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and 3075468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs 3076468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point. 3077468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 30780266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { 30791a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING 30806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov struct timeval t0, t1; 30816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t0, 0); 30821a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif 30831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 308466c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes // Sanitize the environment. 308566c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes __libc_init_AT_SECURE(args); 3086be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 30870b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov // Initialize system properties 30880b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov __system_properties_init(); // may use 'environ' 30890b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov 30906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov debuggerd_init(); 30911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 30926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Get a few environment variables. 309366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes const char* LD_DEBUG = getenv("LD_DEBUG"); 30946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (LD_DEBUG != nullptr) { 30956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_ld_debug_verbosity = atoi(LD_DEBUG); 30966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3097be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 309866c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes // These should have been sanitized by __libc_init_AT_SECURE, but the test 30996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // doesn't cost us anything. 31006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpath_env = nullptr; 31016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpreload_env = nullptr; 310266c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes if (!getauxval(AT_SECURE)) { 310366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes ldpath_env = getenv("LD_LIBRARY_PATH"); 310466c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes ldpreload_env = getenv("LD_PRELOAD"); 31056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 31061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3107bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#if !defined(__LP64__) 3108bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov if (personality(PER_LINUX32) == -1) { 3109bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno)); 3110bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov } 3111bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#endif 3112bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov 31136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov INFO("[ android linker & debugger ]"); 31141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 311507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL); 31166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 31176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 31186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 31191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* bootstrap the link map, the main exe always needs to be first */ 3121ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->set_main_executable(); 31226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(si->link_map_head); 31231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = 0; 31256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_name = args.argv[0]; 31266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = nullptr; 31276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = nullptr; 31281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_map = map; 31306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map; 31311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_linker_info_for_gdb(linker_base); 31331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract information passed from the kernel. 31356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR)); 31366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phnum = args.getauxval(AT_PHNUM); 31376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->entry = args.getauxval(AT_ENTRY); 31381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Compute the value of si->base. We can't rely on the fact that 31406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * the first entry is the PHDR because this will not be true 31416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * for certain executables (e.g. some in the NDK unit test suite) 31426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 31436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = 0; 31446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->size = phdr_table_get_load_size(si->phdr, si->phnum); 31456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = 0; 31466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t i = 0; i < si->phnum; ++i) { 31476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->phdr[i].p_type == PT_PHDR) { 31486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr; 31496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset; 31506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 31518180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner } 31526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 31536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->dynamic = nullptr; 31541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); 31566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (elf_hdr->e_type != ET_DYN) { 31576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n"); 31586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 31596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 31602aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich 31616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). 31626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_LIBRARY_PATH(ldpath_env); 31636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_PRELOAD(ldpreload_env); 31644fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 31656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov somain = si; 31665ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel 31676718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov if (!si->prelink_image()) { 31686718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 31696718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov exit(EXIT_FAILURE); 31706718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov } 317114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 3172d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // add somain to global group 3173d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); 3174d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 31756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Load ld_preloads and dependencies. 31766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov StringLinkedList needed_library_name_list; 31776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t needed_libraries_count = 0; 31786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t ld_preloads_count = 0; 3179d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 3180d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov for (const auto& ld_preload_name : g_ld_preload_names) { 3181d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov needed_library_name_list.push_back(ld_preload_name.c_str()); 31826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 318353ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov ++ld_preloads_count; 31846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 318514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 31866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for_each_dt_needed(si, [&](const char* name) { 31876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.push_back(name); 31886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 31896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov }); 319014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 31916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* needed_library_names[needed_libraries_count]; 319214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 31936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov memset(needed_library_names, 0, sizeof(needed_library_names)); 31946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); 319514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 3196d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (needed_libraries_count > 0 && 3197d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov !find_libraries(si, needed_library_names, needed_libraries_count, nullptr, 3198d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { 31996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 32006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 3201ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else if (needed_libraries_count == 0) { 3202ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) { 3203ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 3204ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov exit(EXIT_FAILURE); 3205ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 3206ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->increment_ref_count(); 32076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 32081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 32096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov add_vdso(args); 3210c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 3211279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov { 3212279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard guard; 32139181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 3214279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov si->call_pre_init_constructors(); 3215279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 3216279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov /* After the prelink_image, the si->load_bias is initialized. 3217279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * For so lib, the map->l_addr will be updated in notify_gdb_of_load. 3218279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * We need to update this value for so exe here. So Unwind_Backtrace 3219279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * for some arch like x86 could work correctly within so exe. 3220279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov */ 3221279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov map->l_addr = si->load_bias; 3222279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov si->call_constructors(); 3223279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 3224e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 32251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING 32266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t1, nullptr); 32276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( 32286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - 32296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); 32301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 32311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 32326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0], 32336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocAbsolute], 32346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocRelative], 32356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocCopy], 32366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocSymbol]); 32371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 32381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 32396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 32406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned n; 32416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned i; 32426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned count = 0; 32436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (n = 0; n < 4096; n++) { 32446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (bitmask[n]) { 32456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned x = bitmask[n]; 3246e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__) 32476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 32; i++) { 3248e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else 32496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 8; i++) { 3250e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif 32516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (x & 1) { 32526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count++; 32536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 32546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov x >>= 1; 32551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 32566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 32571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 32586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4); 32596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 32601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 32611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 32621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES 32636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fflush(stdout); 32641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 32651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3266b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry)); 32676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return si->entry; 32681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3269468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 3270bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only 3271bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library 3272bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself. 3273bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * 3274bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input: 3275bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * elf -> address of ELF header, assumed to be at the start of the file. 3276bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return: 3277bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * load bias, i.e. add the value of any p_vaddr in the file to get 3278bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * the corresponding address in memory. 3279bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */ 32800266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) { 32810266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) offset = elf->e_phoff; 3282b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov const ElfW(Phdr)* phdr_table = 3283b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset); 32840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum; 3285fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 32860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) { 3287fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (phdr->p_type == PT_LOAD) { 32880266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr; 3289bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner } 3290fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 3291fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return 0; 3292bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner} 3293bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner 3294efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start(); 3295efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 3296468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 3297468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This 3298468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and 3299468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation(). 3300468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * 3301468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own 3302468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern 3303468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault. 3304468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 33050266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) { 330642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes KernelArgumentBlock args(raw_args); 330742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 33080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) linker_addr = args.getauxval(AT_BASE); 3309efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); 33100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); 3311faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); 331242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 3313aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov soinfo linker_so(nullptr, nullptr, 0, 0); 331442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 3315efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // If the linker is not acting as PT_INTERP entry_point is equal to 3316efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // _start. Which means that the linker is running as an executable and 3317efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // already linked by PT_INTERP. 3318efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // 3319efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // This happens when user tries to run 'adb shell /system/bin/linker' 3320efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // see also https://code.google.com/p/android/issues/detail?id=63174 3321efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) { 3322efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]); 3323efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov } 3324efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 332542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.base = linker_addr; 332642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); 332742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); 3328851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov linker_so.dynamic = nullptr; 332942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phdr = phdr; 333042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phnum = elf_hdr->e_phnum; 3331ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov linker_so.set_linker_flag(); 333242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 3333d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // This might not be obvious... The reasons why we pass g_empty_list 3334d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // in place of local_group here are (1) we do not really need it, because 3335d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // linker is built with DT_SYMBOLIC and therefore relocates its symbols against 3336d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // itself without having to look into local_group and (2) allocators 3337d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // are not yet initialized, and therefore we cannot use linked_list.push_* 3338d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // functions at this point. 3339047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) { 334042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // It would be nice to print an error message, but if the linker 334142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // can't link itself, there's no guarantee that we'll be able to 3342b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // call write() (because it involves a GOT reference). We may as 3343b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // well try though... 3344b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes const char* msg = "CANNOT LINK EXECUTABLE: "; 3345b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, msg, strlen(msg)); 3346b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf)); 3347b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, "\n", 1); 3348b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes _exit(EXIT_FAILURE); 334942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes } 3350468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 335114241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov __libc_init_tls(args); 335214241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov 3353efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // Initialize the linker's own global variables 3354047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov linker_so.call_constructors(); 33554151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov 33560d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // Initialize static variables. Note that in order to 33570d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // get correct libdl_info we need to call constructors 33580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // before get_libdl_info(). 33590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov solist = get_libdl_info(); 33600d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov sonext = get_libdl_info(); 33610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 336242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // We have successfully fixed our own relocations. It's safe to run 336342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // the main part of the linker now. 33641728b2396591853345507a063ed6075dfd251706Elliott Hughes args.abort_message_ptr = &g_abort_message; 33650266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr); 33665419b9474753d25dff947c7740532f86d130c0beElliott Hughes 3367611f95689e1012283bd11917003d3740d3ce532dElliott Hughes INFO("[ jumping to _start ]"); 3368611f95689e1012283bd11917003d3740d3ce532dElliott Hughes 336942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // Return the address that the calling assembly stub should jump to. 337042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes return start_address; 3371468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich} 3372