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> 404688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h> 411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 420d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new> 43d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <string> 44d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <vector> 450d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 464688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers. 47eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h" 48eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h" 49eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h" 5014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/ScopeGuard.h" 5114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/UniquePtr.h" 521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h" 54c9ce70d7838b6aae074fc3615cdf04e5c9ac612aDmitriy Ivanov#include "linker_block_allocator.h" 551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h" 5618870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov#include "linker_sleb128.h" 5723363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h" 58cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#include "linker_relocs.h" 59fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker_reloc_iterators.h" 60aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin#include "ziparchive/zip_archive.h" 611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6266c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughesextern void __libc_init_AT_SECURE(KernelArgumentBlock&); 631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6466c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes// Override macros to use C++ style casts. 651649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#undef ELF_ST_TYPE 661649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf) 671649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov 680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); 691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 70600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<soinfo> g_soinfo_allocator; 71600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator; 72ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 73d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist; 74d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext; 756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info 761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 771728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = { 784eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__) 79011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes "/vendor/lib64", 80011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes "/system/lib64", 81011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else 82124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes "/vendor/lib", 83124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes "/system/lib", 84011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif 85851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov nullptr 86124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes}; 87124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes 882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymNotNeeded = 0; 892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymGlobal = 1; 902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 91d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_library_paths; 92d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_preload_names; 93a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 94d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<soinfo*> g_ld_preloads; 954fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 961728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity; 971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 98851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd. 990d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 101bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t { 1026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int count[kRelocMax]; 103bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}; 104bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 105bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats; 106bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 107114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind kind) { 1086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++linker_stats.count[kind]; 109bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 110bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else 111114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind) { 112bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 116114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovuint32_t bitmask[4096]; 1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1192e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768]; 1202e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 121650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() { 1225419b9474753d25dff947c7740532f86d130c0beElliott Hughes return &__linker_dl_err_buf[0]; 1232e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin} 1242e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 125650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() { 126650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes return sizeof(__linker_dl_err_buf); 127650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes} 128650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes 1296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified 1306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity. 13120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovextern "C" 13220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(); 1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1341728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER; 13520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic r_debug _r_debug = 13620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0}; 13720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov 1383a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0; 1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1403a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) { 1416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Copy the necessary fields into the debug structure. 1426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(info->link_map_head); 1436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = info->load_bias; 144aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov // link_map l_name field is not const. 145aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov map->l_name = const_cast<char*>(info->get_realpath()); 1466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_ld = info->dynamic; 1476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 1486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Stick the new library at the end of the list. 1496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // gdb tends to care more about libc than it does 1506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // about leaf libraries, and ordering it this way 1516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // reduces the back-and-forth over the wire. 1526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (r_debug_tail) { 1536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail->l_next = map; 1546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = r_debug_tail; 1556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = 0; 1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 1576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_map = map; 1586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = 0; 1596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = 0; 1606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map; 1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 164bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) { 1656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(info->link_map_head); 1665e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 1676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (r_debug_tail == map) { 1686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map->l_prev; 1696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1705e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 1716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (map->l_prev) { 1726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev->l_next = map->l_next; 1736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (map->l_next) { 1756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next->l_prev = map->l_prev; 1766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1775e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev} 1785e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 179bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) { 180ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (info->is_main_executable()) { 1816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // GDB already knows about the main executable 1826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 1836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ScopedPthreadMutexLocker locker(&g__r_debug_mutex); 1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_ADD; 1886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov insert_soinfo_into_debug_map(info); 1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_CONSISTENT; 1936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 1945e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev} 1955e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 196bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) { 197ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (info->is_main_executable()) { 1986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // GDB already knows about the main executable 1996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2015e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ScopedPthreadMutexLocker locker(&g__r_debug_mutex); 2035e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_DELETE; 2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2065e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov remove_soinfo_from_debug_map(info); 2085e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_CONSISTENT; 2106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21318a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() { 2143a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes _r_debug.r_state = r_debug::RT_ADD; 2153a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes rtld_db_dlactivity(); 2163a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes _r_debug.r_state = r_debug::RT_CONSISTENT; 2173a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes rtld_db_dlactivity(); 2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 220d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() { 221d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return g_soinfo_links_allocator.alloc(); 222d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 223d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 224d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) { 225d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov g_soinfo_links_allocator.free(entry); 226d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 227d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 22820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat, 22920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov off64_t file_offset, uint32_t rtld_flags) { 230aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (strlen(name) >= PATH_MAX) { 231ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn DL_ERR("library name \"%s\" too long", name); 232851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 233ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn } 234ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 23507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags); 236d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 237ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext->next = si; 238ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext = si; 2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 240ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("name %s: allocated soinfo @ %p", name, si); 241ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn return si; 2421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 244faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) { 2456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 2466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2484688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 2496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->base != 0 && si->size != 0) { 2506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov munmap(reinterpret_cast<void*>(si->base), si->size); 2516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 252d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo *prev = nullptr, *trav; 2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 255b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si); 2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (trav = solist; trav != nullptr; trav = trav->next) { 2586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == si) { 2596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 2616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev = trav; 2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 263ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == nullptr) { 2656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // si was not in solist 266b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si); 2676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // clear links to/from si 2716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->remove_all_links(); 272d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // prev will never be null, because the first entry in solist is 2746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // always the static libdl_info. 2756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev->next = si->next; 2766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == sonext) { 2776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sonext = prev; 2786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 279d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov 280a5bb841df799e10e7d0ae3202b097da8a1c23507Dmitriy Ivanov si->~soinfo(); 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. 356f7d5bf334dc4bc5b7399d4c8268e1b0bf676548fDmitriy Ivanovint do_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. 129606700b2b5e92a365505b15d0d05e2d5b0706c511Dmitriy Ivanov ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size); 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 } 1924de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } else { // We got a definition. 1925de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__) 1926de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov // When relocating dso with text_relocation .text segment is 1927de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov // not executable. We need to restore elf flags before resolving 1928de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov // STT_GNU_IFUNC symbol. 1929de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov bool protect_segments = has_text_relocations && 1930de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov lsi == this && 1931de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC; 1932de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (protect_segments) { 1933de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 1934de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov DL_ERR("can't protect segments for \"%s\": %s", 1935de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov get_realpath(), strerror(errno)); 1936de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov return false; 1937de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 1938de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 1939de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif 19409aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 1941de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__) 1942de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (protect_segments) { 1943de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 1944de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 1945de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov get_realpath(), strerror(errno)); 1946de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov return false; 1947de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 1948de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 1949de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif 1950c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1951c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes count_relocation(kRelocSymbol); 1952c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1953c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1954c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 1955cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_JUMP_SLOT: 1956e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1957bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1958bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n", 1959bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 1960bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(sym_addr + addend), sym_name); 1961bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov 1962bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend); 1963e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1964cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_GLOB_DAT: 1965e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1966bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1967bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n", 1968bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 1969bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(sym_addr + addend), sym_name); 1970bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend); 1971e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1972cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_RELATIVE: 1973cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov count_relocation(kRelocRelative); 1974bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1975bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n", 1976bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 197718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reinterpret_cast<void*>(load_bias + addend)); 197818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend); 1979cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov break; 1980cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_IRELATIVE: 1981cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov count_relocation(kRelocRelative); 1982bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 1983bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n", 1984bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 198518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reinterpret_cast<void*>(load_bias + addend)); 1986de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov { 1987de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__) 1988de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov // When relocating dso with text_relocation .text segment is 1989de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov // not executable. We need to restore elf flags for this 1990de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov // particular call. 1991de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (has_text_relocations) { 1992de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 1993de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov DL_ERR("can't protect segments for \"%s\": %s", 1994de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov get_realpath(), strerror(errno)); 1995de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov return false; 1996de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 1997de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 1998de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif 1999de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend); 2000de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__) 2001de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov // Unprotect it afterwards... 2002de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (has_text_relocations) { 2003de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 2004de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 2005de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov get_realpath(), strerror(errno)); 2006de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov return false; 2007de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 2008de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 2009de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif 2010de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr; 2011de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov } 2012cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov break; 2013cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov 2014cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__aarch64__) 20156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 2016e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2017bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20180266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n", 2019bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), sym_name); 2020bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend); 2021e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 2023e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2024bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n", 2026bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), sym_name); 202720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 202820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc); 202920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN); 203020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX); 203120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if ((min_value <= (reloc_value + (sym_addr + addend))) && 203220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ((reloc_value + (sym_addr + addend)) <= max_value)) { 203320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend); 203420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 203520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 203620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov (reloc_value + (sym_addr + addend)), min_value, max_value); 203720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 203820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2039e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2040e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 2042e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2043bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20440266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n", 2045bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), sym_name); 204620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 204720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc); 204820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); 204920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX); 205020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if ((min_value <= (reloc_value + (sym_addr + addend))) && 205120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ((reloc_value + (sym_addr + addend)) <= max_value)) { 205220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend); 205320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 205420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 205520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reloc_value + (sym_addr + addend), min_value, max_value); 205620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 205720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2058e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2059e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL64: 2061e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2062bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20630266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n", 2064bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset, sym_name); 2065bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset; 2066e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL32: 2068e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2069bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n", 2071bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset, sym_name); 207220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 207320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc); 207420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN); 207520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX); 207620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) && 207720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) { 207820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset); 207920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 208020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 208120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value); 208220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 208320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2084e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2085e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 20866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL16: 2087e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2088bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 20890266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n", 2090bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset, sym_name); 209120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 209220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc); 209320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); 209420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX); 209520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) && 209620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) { 209720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset); 209820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 209920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 210020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value); 210120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 210220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2103e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2104e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 2105e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 21066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_COPY: 210776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich /* 210876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * ET_EXEC is not supported so this should not happen. 210976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 2110aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf 211176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 2112aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * Section 4.6.11 "Dynamic relocations" 211376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * R_AARCH64_COPY may only appear in executable objects where e_type is 211476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * set to ET_EXEC. 211576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich */ 2116b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath()); 2117114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 21186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_TPREL64: 21190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", 2120bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset); 2121e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 21226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_DTPREL32: 21230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n", 2124bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset); 2125e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 2126e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__) 21276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_32: 21286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 2129bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 21306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 21316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 2132bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; 21336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_64: 21356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 2136bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 21376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 21386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 2139bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; 21406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_PC32: 21426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 2143bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 21446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", 21456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc), 21466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name); 2147bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc; 21486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2149bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__) 21506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_ABS32: 21516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 21526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name); 21546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 21556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_REL32: 21576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 21586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s", 21606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, sym_addr, rel->r_offset, sym_name); 21616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset; 21626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_COPY: 21646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 21656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * ET_EXEC is not supported so this should not happen. 21666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 21676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 21686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 2169aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * Section 4.6.1.10 "Dynamic relocations" 21706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * R_ARM_COPY may only appear in executable objects where e_type is 21716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * set to ET_EXEC. 21726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 2173b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath()); 2174114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 21754eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 21766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_32: 21776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 21786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); 21806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 21816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_PC32: 21836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 21846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 21856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", 21866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); 21876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc); 21886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21894eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 21906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 21916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); 21926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2193d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 21946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 2196d7daacb46372132ae3f0121647074936c304b572Raghu Gandham} 2197114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#endif // !defined(__mips__) 2198d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 219920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid soinfo::call_array(const char* array_name __unused, linker_function_t* functions, 220020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov size_t count, bool reverse) { 2201851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (functions == nullptr) { 2202d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 2203d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 22048215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2205b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath()); 22068215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2207ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int begin = reverse ? (count - 1) : 0; 2208ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int end = reverse ? -1 : count; 2209ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int step = reverse ? -1 : 1; 22108215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2211ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes for (int i = begin; i != end; i += step) { 2212ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]); 2213047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("function", functions[i]); 2214d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 2215d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2216b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath()); 22171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 22181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2219047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_function(const char* function_name __unused, linker_function_t function) { 2220851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) { 2221d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 2222d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 2223d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2224b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath()); 2225d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes function(); 2226b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath()); 22279181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov} 22289181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 2229047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_pre_init_constructors() { 22308147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_PREINIT_ARRAY functions are called before any other constructors for executables, 22318147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // but ignored in a shared library. 2232047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false); 2233d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 2234e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 2235047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_constructors() { 2236d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes if (constructors_called) { 2237d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 2238d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 2239e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 2240d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // We set constructors_called before actually calling the constructors, otherwise it doesn't 2241d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // protect against recursive constructor calls. One simple example of constructor recursion 2242d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so: 2243d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 1. The program depends on libc, so libc's constructor is called here. 2244d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so. 2245d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 3. dlopen() calls the constructors on the newly created 2246d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // soinfo for libc_malloc_debug_leak.so. 2247d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 4. The debug .so depends on libc, so CallConstructors is 2248d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // called again with the libc soinfo. If it doesn't trigger the early- 2249d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // out above, the libc constructor will be called again (recursively!). 2250d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes constructors_called = true; 2251d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2252ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!is_main_executable() && preinit_array_ != nullptr) { 22538147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // The GNU dynamic linker silently ignores these, but we warn the developer. 2254c620059479c47a78d57086d73726c9adc2f337adElliott Hughes PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!", 2255b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), preinit_array_count_); 2256d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 22571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2258d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov get_children().for_each([] (soinfo* si) { 2259047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->call_constructors(); 2260d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 22611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2262b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("\"%s\": calling constructors", get_realpath()); 22638147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 22648147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_INIT should be called before DT_INIT_ARRAY if both are present. 2265047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("DT_INIT", init_func_); 2266047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false); 2267e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov} 22688215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 2269047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_destructors() { 227014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!constructors_called) { 227114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return; 227214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 2273b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("\"%s\": calling destructors", get_realpath()); 22748147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 22758147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI_ARRAY must be parsed in reverse order. 2276047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true); 22778147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 22788147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI should be called after DT_FINI_ARRAY if both are present. 2279047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("DT_FINI", fini_func_); 2280b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 2281b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // This is needed on second call to dlopen 2282b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // after library has been unloaded with RTLD_NODELETE 2283b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov constructors_called = false; 22841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 22851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2286d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) { 22870d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2288047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov child->parents_.push_back(this); 2289047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->children_.push_back(child); 2290d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2291d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2292d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2293d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() { 22940d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (!has_min_version(0)) { 2295d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return; 2296d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2297d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2298d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 1. Untie connected soinfos from 'this'. 2299047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov children_.for_each([&] (soinfo* child) { 2300047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov child->parents_.remove_if([&] (const soinfo* parent) { 2301d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return parent == this; 2302d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2303d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2304d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2305047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parents_.for_each([&] (soinfo* parent) { 2306047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parent->children_.remove_if([&] (const soinfo* child) { 2307d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return child == this; 2308d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2309d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 2310d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2311d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 2. Once everything untied - clear local lists. 2312047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parents_.clear(); 2313047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov children_.clear(); 2314d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2315d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2316d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovdev_t soinfo::get_st_dev() const { 23170d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2318047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return st_dev_; 2319d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2320d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 23210d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 2322d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}; 2323d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2324d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovino_t soinfo::get_st_ino() const { 23250d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2326047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return st_ino_; 2327d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2328d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 23290d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 2330d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2331d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2332d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovoff64_t soinfo::get_file_offset() const { 233307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if (has_min_version(1)) { 2334047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return file_offset_; 233507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 233607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 233707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return 0; 233807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov} 233907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 2340d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_rtld_flags() const { 2341e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (has_min_version(1)) { 2342047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return rtld_flags_; 2343e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 2344e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 2345e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov return 0; 2346e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov} 2347e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 2348d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_dt_flags_1() const { 2349d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (has_min_version(1)) { 2350047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return dt_flags_1_; 2351d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2352d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2353d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return 0; 2354d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 2355618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 2356d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovvoid soinfo::set_dt_flags_1(uint32_t dt_flags_1) { 2357d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (has_min_version(1)) { 2358d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((dt_flags_1 & DF_1_GLOBAL) != 0) { 2359047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rtld_flags_ |= RTLD_GLOBAL; 2360d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2361d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2362d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((dt_flags_1 & DF_1_NODELETE) != 0) { 2363047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rtld_flags_ |= RTLD_NODELETE; 2364d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2365d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2366047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov dt_flags_1_ = dt_flags_1; 2367d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 2368d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 2369d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2370aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_realpath() const { 237169a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__) 2372aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (has_min_version(2)) { 2373aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return realpath_.c_str(); 2374aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } else { 2375aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return old_name_; 2376aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 2377aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else 2378aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return realpath_.c_str(); 2379aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif 2380aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov} 2381aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 2382aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_soname() const { 238369a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__) 2384618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov if (has_min_version(2)) { 2385618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov return soname_; 2386618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } else { 2387aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return old_name_; 2388618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } 2389aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else 2390aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return soname_; 2391aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif 2392618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov} 2393618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 239414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if 2395d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set. 2396d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list; 2397d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2398d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() { 23990d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 2400047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return children_; 2401d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2402d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 24030d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return g_empty_list; 2404d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2405d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 24062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst soinfo::soinfo_list_t& soinfo::get_children() const { 24072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(0)) { 24082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return children_; 24092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 24102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 24112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return g_empty_list; 24122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 24132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 241414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() { 2415047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (has_min_version(0)) { 2416047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return parents_; 241714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 241814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2419047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return g_empty_list; 242014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 242114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 24222a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const { 24239aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { 24249aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return call_ifunc_resolver(s->st_value + load_bias); 24259aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov } 24269aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 24279aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return static_cast<ElfW(Addr)>(s->st_value + load_bias); 24289aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov} 24299aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 24306cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const { 2431047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (has_min_version(1) && (index >= strtab_size_)) { 2432aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", 2433b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strtab_size_, index); 24346cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 24356cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 2436047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return strtab_ + index; 24376cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov} 24386cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 2439ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovbool soinfo::is_gnu_hash() const { 2440ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_GNU_HASH) != 0; 2441ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 2442ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 24431b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const { 2444d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; 24451b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov} 2446d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2447ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_linked() const { 2448ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_LINKED) != 0; 2449ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2450ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2451ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_main_executable() const { 2452ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_EXE) != 0; 2453ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2454ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2455ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linked() { 2456ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_LINKED; 2457ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2458ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2459ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linker_flag() { 2460ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_LINKER; 2461ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2462ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2463ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_main_executable() { 2464ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_EXE; 2465ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2466ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2467ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::increment_ref_count() { 2468ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_->ref_count_++; 2469ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2470ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2471ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsize_t soinfo::decrement_ref_count() { 2472ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return --local_group_root_->ref_count_; 2473ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2474ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2475ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsoinfo* soinfo::get_local_group_root() const { 2476ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return local_group_root_; 2477ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 2478ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 247904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// This function returns api-level at the time of 248004f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// dlopen/load. Note that libraries opened by system 248104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// will always have 'current' api level. 248204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanovuint32_t soinfo::get_target_sdk_version() const { 248304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if (!has_min_version(2)) { 248404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov return __ANDROID_API__; 248504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov } 248604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov 248704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov return local_group_root_->target_sdk_version_; 248804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov} 248904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov 2490047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::prelink_image() { 2491e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian /* Extract dynamic section */ 2492e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian ElfW(Word) dynamic_flags = 0; 2493e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags); 2494498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov 24956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can't log anything until the linker is relocated */ 2496ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov bool relocating_linker = (flags_ & FLAG_LINKER) != 0; 24976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 249853ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov INFO("[ linking %s ]", get_realpath()); 2499ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_); 25006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 25016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 25026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dynamic == nullptr) { 2503b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner if (!relocating_linker) { 2504b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath()); 2505b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner } 25066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 25076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 25086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 25096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("dynamic = %p", dynamic); 251063f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner } 25116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 251263f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 25134eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 25146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, 25156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov &ARM_exidx, &ARM_exidx_count); 251663f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif 251763f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 25186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract useful information from dynamic section. 2519618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // Note that: "Except for the DT_NULL element at the end of the array, 2520618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // and the relative order of DT_NEEDED elements, entries may appear in any order." 2521618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // 2522618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html 25236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov uint32_t needed_count = 0; 25246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 25256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", 25266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 25276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (d->d_tag) { 25284a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SONAME: 2529618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // this is parsed after we have strtab initialized (see below). 25304a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2531ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_HASH: 2533047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 2534047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 2535047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8); 2536047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4); 25376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2538ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2539ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov case DT_GNU_HASH: 25403597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 2541ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // skip symndx 2542047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2]; 2543047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3]; 2544ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2545047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16); 25463597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_); 2547ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // amend chain for symndx = header[1] 254820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov gnu_chain_ = gnu_bucket_ + gnu_nbucket_ - 254920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 2550ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2551047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!powerof2(gnu_maskwords_)) { 255220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two", 2553aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov gnu_maskwords_, get_realpath()); 2554ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return false; 2555ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 2556047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov --gnu_maskwords_; 2557ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 2558ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_GNU_HASH; 2559ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov break; 2560ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 25616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_STRTAB: 2562047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr); 25636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2564ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25656cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_STRSZ: 2566047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov strtab_size_ = d->d_un.d_val; 25676cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 2568ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMTAB: 2570047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr); 25716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2572ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25734a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SYMENT: 25744a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Sym))) { 2575aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("invalid DT_SYMENT: %zd in \"%s\"", 2576aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov static_cast<size_t>(d->d_un.d_val), get_realpath()); 25774a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 25784a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 25794a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2580ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTREL: 2582513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA) 2583513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov if (d->d_un.d_val != DT_RELA) { 2584aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath()); 2585513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov return false; 2586513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov } 2587513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else 25886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val != DT_REL) { 2589aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath()); 25906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 25916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2592c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 2593513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 2594ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 25956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_JMPREL: 25964eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 2597047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 2598c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 2599047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 2600c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 26016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2602ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTRELSZ: 26044eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 2605047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela)); 2606c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 2607047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel)); 2608c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 26096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2610ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTGOT: 26124a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__) 26136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Used by mips and mips64. 2614047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr); 2615c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 26164a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // Ignore for other platforms... (because RTLD_LAZY is not supported) 26174a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2618ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_DEBUG: 26206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_DEBUG entry to the address of _r_debug for GDB 26216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // if the dynamic table is writable 26229918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64 26239918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree. 262414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as 26259918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable. 26269918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__)) 26276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((dynamic_flags & PF_W) != 0) { 26286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug); 26296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 26309918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif 2631c6292ea39cce054175e4f9f797c05aeb8da0ac4bDmitriy Ivanov break; 26324eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 26336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 2634047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 26356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2636ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELASZ: 2638047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela)); 26396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2640ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 264118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELA: 264218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr); 264318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 264418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 264518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELASZ: 264618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_size_ = d->d_un.d_val; 264718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 264818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 264918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_REL: 2650aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath()); 265118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 265218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 265318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELSZ: 2654aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath()); 265518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 265618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 26574a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELAENT: 26584a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rela))) { 2659f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val)); 26604a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 26614a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 26624a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2663ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2664ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // ignored (see DT_RELCOUNT comments for details) 26654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELACOUNT: 26664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2667ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 2669aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_REL in \"%s\"", get_realpath()); 26706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2671ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 2673aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath()); 26746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 267518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 2676c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 26776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 2678047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 26796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2680ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 2682047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel)); 26836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2684ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 26854a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELENT: 26864a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rel))) { 2687f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val)); 26884a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 26894a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 26904a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2691ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 269218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_REL: 269318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr); 269418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 269518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 269618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELSZ: 269718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_size_ = d->d_un.d_val; 269818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 269918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 270018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELA: 2701aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath()); 270218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 270318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 270418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELASZ: 2705aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath()); 270618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 270718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 2708ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // "Indicates that all RELATIVE relocations have been concatenated together, 2709ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // and specifies the RELATIVE relocation count." 2710ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // 2711ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // TODO: Spec also mentions that this can be used to optimize relocation process; 2712ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Not currently used by bionic linker - ignored. 27134a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELCOUNT: 27144a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 271518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 27166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 2717aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath()); 27186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 271918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 272018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_RELASZ: 2721aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath()); 272218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 272318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 2724c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 27256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT: 2726047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 2727aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_); 27286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2729ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI: 2731047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 2732aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_); 27336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2734ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAY: 2736047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 2737aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_); 27386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2739ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAYSZ: 27411649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 27426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2743ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAY: 2745047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 2746aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_); 27476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2748ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAYSZ: 27501649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 27516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2752ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAY: 2754047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 2755aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_); 27566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2757ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAYSZ: 27591649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 27606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2761ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_TEXTREL: 276356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__) 2764aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath()); 27656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 276656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else 276756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov has_text_relocations = true; 276856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov break; 276956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 2770ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMBOLIC: 277296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 27736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2774ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_NEEDED: 27766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_count; 27776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2778ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FLAGS: 27806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val & DF_TEXTREL) { 278156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__) 2782aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath()); 27836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 278456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else 278556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov has_text_relocations = true; 278656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 27876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 278896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (d->d_un.d_val & DF_SYMBOLIC) { 278996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 279096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 27916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2792ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 27936cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_FLAGS_1: 2794d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov set_dt_flags_1(d->d_un.d_val); 27956cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 2796d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) { 2797ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val)); 27986cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 27996cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 28004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 28016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_MAP: 28026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. 28036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 28046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr); 28056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *dp = &_r_debug; 28066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 28076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2808688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham case DT_MIPS_RLD_MAP2: 2809688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB. 2810688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham { 281120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>( 281220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val); 2813688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham *dp = &_r_debug; 2814688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham } 2815688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham break; 2816ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 28176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_VERSION: 28186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_FLAGS: 28196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_BASE_ADDRESS: 28206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_UNREFEXTNO: 28216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2822d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 28236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_SYMTABNO: 2824047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_symtabno_ = d->d_un.d_val; 28256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2826d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 28276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_LOCAL_GOTNO: 2828047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_local_gotno_ = d->d_un.d_val; 28296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2830d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 28316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_GOTSYM: 2832047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_gotsym_ = d->d_un.d_val; 28336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 28344eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 2835ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Ignored: "Its use has been superseded by the DF_BIND_NOW flag" 2836ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov case DT_BIND_NOW: 2837ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov break; 2838ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2839513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERSYM: 28402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr); 28412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 28422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 2843513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEF: 28442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef_ptr_ = load_bias + d->d_un.d_ptr; 28452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 2846513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEFNUM: 28472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef_cnt_ = d->d_un.d_val; 28482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 28492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 2850e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko case DT_VERNEED: 28512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed_ptr_ = load_bias + d->d_un.d_ptr; 28522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 28532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 2854e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko case DT_VERNEEDNUM: 28552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed_cnt_ = d->d_un.d_val; 2856513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 2857d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 28586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 28598f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (!relocating_linker) { 2860aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(), 28618f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 28628f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 28636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 28641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 28656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 28661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 28676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", 2868047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov reinterpret_cast<void*>(base), strtab_, symtab_); 28691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 28706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Sanity checks. 28716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (relocating_linker && needed_count != 0) { 28726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); 28736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 28753597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov if (nbucket_ == 0 && gnu_nbucket_ == 0) { 2876aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" " 2877b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov "(new hash type from the future?)", get_realpath()); 28786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2880047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (strtab_ == 0) { 2881b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath()); 28826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2884047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (symtab_ == 0) { 2885b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath()); 28866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 28876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 288838c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov 288907f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov // second pass - parse entries relying on strtab 289007f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 289107f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov if (d->d_tag == DT_SONAME) { 289207f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov soname_ = get_string(d->d_un.d_val); 289307f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#if defined(__work_around_b_19059885__) 289407f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov strlcpy(old_name_, soname_, sizeof(old_name_)); 289507f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#endif 289607f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov break; 289707f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov } 289807f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov } 289907f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov 290038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov // Before M release linker was using basename in place of soname. 290104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // In the case when dt_soname is absent some apps stop working 290238c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov // because they can't find dt_needed library by soname. 290338c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov // This workaround should keep them working. (applies only 290404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // for apps targeting sdk version <=22). Make an exception for 290504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov // the main executable and linker; they do not need to have dt_soname 290604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 && 290704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov get_application_target_sdk_version() <= 22) { 290838c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov soname_ = basename(realpath_.c_str()); 290938c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"", 291038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov get_realpath(), soname_); 291138c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov } 29126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 291314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 29141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 291518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovbool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group, 291618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const android_dlextinfo* extinfo) { 29171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2918ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_ = local_group.front(); 2919ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (local_group_root_ == nullptr) { 2920ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_ = this; 2921ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 2922ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 292304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) { 292404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov target_sdk_version_ = get_application_target_sdk_version(); 292504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov } 292604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov 2927f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov VersionTracker version_tracker; 2928f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov 2929f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!version_tracker.init(this)) { 2930f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov return false; 2931f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov } 2932f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov 293356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__) 293456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (has_text_relocations) { 29353e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov // Fail if app is targeting sdk version > 22 29363e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov // TODO (dimitry): remove != __ANDROID_API__ check once http://b/20020312 is fixed 29373e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov if (get_application_target_sdk_version() != __ANDROID_API__ 29383e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov && get_application_target_sdk_version() > 22) { 29393e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov DL_ERR("%s: has text relocations", get_realpath()); 29403e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov return false; 29413e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov } 294256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // Make segments writable to allow text relocations to work properly. We will later call 294356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // phdr_table_protect_segments() after all of them are applied and all constructors are run. 294456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_WARN("%s has text relocations. This is wasting memory and prevents " 2945b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov "security hardening. Please fix.", get_realpath()); 294656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 294756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 2948b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 294956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov return false; 295056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 295156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 295256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 295356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov 295418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (android_relocs_ != nullptr) { 295518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov // check signature 295618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (android_relocs_size_ > 3 && 295718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[0] == 'A' && 295818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[1] == 'P' && 295918870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov android_relocs_[2] == 'S' && 296018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[3] == '2') { 2961b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ android relocating %s ]", get_realpath()); 296218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 296318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov bool relocated = false; 296418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const uint8_t* packed_relocs = android_relocs_ + 4; 296518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const size_t packed_relocs_size = android_relocs_size_ - 4; 296618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 296718870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov relocated = relocate( 2968f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov version_tracker, 296918870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov packed_reloc_iterator<sleb128_decoder>( 297018870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov sleb128_decoder(packed_relocs, packed_relocs_size)), 297118870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov global_group, local_group); 297218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 297318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (!relocated) { 297418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 297518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 297618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } else { 297718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov DL_ERR("bad android relocation header."); 297818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 297918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 298018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 298118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 29824eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 2983047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (rela_ != nullptr) { 2984b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s ]", get_realpath()); 2985f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 2986f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) { 29876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2988c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 29896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2990047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (plt_rela_ != nullptr) { 2991b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s plt ]", get_realpath()); 2992f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 2993f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) { 29946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 29951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 29966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 29979aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else 2998047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (rel_ != nullptr) { 2999b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s ]", get_realpath()); 3000f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 3001f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) { 30026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 30031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 30046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3005047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (plt_rel_ != nullptr) { 3006b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ relocating %s plt ]", get_realpath()); 3007f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov if (!relocate(version_tracker, 3008f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) { 30096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 3010c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith } 30116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 30129aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif 3013c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 30144eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 3015dc145b510640202a60b0dfaef9d56cd8fc1c05a9Dmitriy Ivanov if (!mips_relocate_got(version_tracker, global_group, local_group)) { 30166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 30176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3018d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif 3019d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 3020b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov DEBUG("[ finished linking %s ]", get_realpath()); 30211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 302256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__) 302356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (has_text_relocations) { 302456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // All relocations are done, we can protect our segments back to read-only. 302556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 302656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_ERR("can't protect segments for \"%s\": %s", 3027b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 302856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov return false; 302956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 303056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 303156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 303256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov 30336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can also turn on GNU RELRO protection */ 30346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { 30356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", 3036b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 30376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 30386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 30399ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich 30406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Handle serializing/sharing the RELRO segment */ 30416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { 30426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, 30436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 30446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", 3045b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 30466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 3047183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) } 30486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { 30496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, 30506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 30516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", 3052b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov get_realpath(), strerror(errno)); 30536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 30546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 30556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3056183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) 30576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov notify_gdb_of_load(this); 30586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 30591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 30601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3061468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 3062c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list. 3063c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers. 3064c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc. 3065c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */ 3066812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) { 30674eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR) 30680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR)); 3069851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (ehdr_vdso == nullptr) { 30700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return; 30710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 3072c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 307307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0); 3074ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 30750266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff); 30760266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phnum = ehdr_vdso->e_phnum; 30770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso); 30780266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->size = phdr_table_get_load_size(si->phdr, si->phnum); 30790266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->load_bias = get_elf_exec_load_bias(ehdr_vdso); 3080ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 3081047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->prelink_image(); 3082047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr); 3083c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif 3084c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov} 3085c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 3086c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/* 3087d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below. 3088d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 30890d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__) 30900d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64" 30910d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else 30920d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker" 30930d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif 3094aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 3095aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// This is done to avoid calling c-tor prematurely 3096aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// because soinfo c-tor needs memory allocator 3097aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// which might be initialized after global variables. 3098aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic uint8_t linker_soinfo_for_gdb_buf[sizeof(soinfo)] __attribute__((aligned(8))); 3099aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic soinfo* linker_soinfo_for_gdb = nullptr; 3100d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3101d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list. 3102d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text" 3103d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to 3104d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol. 3105d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't 3106d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list. 3107d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 3108d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) { 3109aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0); 3110aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 311138263dd91a4b68e2ad0afe458c9a20cb360dafebDmitriy Ivanov linker_soinfo_for_gdb->load_bias = linker_base; 3112d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3113d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov /* 3114d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Set the dynamic field in the link map otherwise gdb will complain with 3115d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * the following: 3116d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * warning: .dynamic section for "/system/bin/linker" is not at the 3117d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * expected address (wrong library or version mismatch?) 3118d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 3119d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base); 3120d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff); 3121d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, 3122aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov &linker_soinfo_for_gdb->dynamic, nullptr); 3123aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov insert_soinfo_into_debug_map(linker_soinfo_for_gdb); 3124d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 3125d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 31260b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanovextern "C" int __system_properties_init(void); 31270b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov 3128d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* 3129468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and 3130468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs 3131468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point. 3132468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 31330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { 31341a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING 31356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov struct timeval t0, t1; 31366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t0, 0); 31371a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif 31381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 313966c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes // Sanitize the environment. 314066c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes __libc_init_AT_SECURE(args); 3141be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 31420b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov // Initialize system properties 31430b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov __system_properties_init(); // may use 'environ' 31440b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov 31456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov debuggerd_init(); 31461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Get a few environment variables. 314866c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes const char* LD_DEBUG = getenv("LD_DEBUG"); 31496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (LD_DEBUG != nullptr) { 31506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_ld_debug_verbosity = atoi(LD_DEBUG); 31516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3152be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 315366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes // These should have been sanitized by __libc_init_AT_SECURE, but the test 31546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // doesn't cost us anything. 31556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpath_env = nullptr; 31566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpreload_env = nullptr; 315766c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes if (!getauxval(AT_SECURE)) { 315866c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes ldpath_env = getenv("LD_LIBRARY_PATH"); 315966c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes ldpreload_env = getenv("LD_PRELOAD"); 31606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 31611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov INFO("[ android linker & debugger ]"); 31631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 316407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL); 31656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 31666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 31676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 31681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* bootstrap the link map, the main exe always needs to be first */ 3170ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->set_main_executable(); 31716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(si->link_map_head); 31721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = 0; 31746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_name = args.argv[0]; 31756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = nullptr; 31766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = nullptr; 31771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_map = map; 31796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map; 31801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_linker_info_for_gdb(linker_base); 31821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract information passed from the kernel. 31846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR)); 31856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phnum = args.getauxval(AT_PHNUM); 31866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->entry = args.getauxval(AT_ENTRY); 31871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Compute the value of si->base. We can't rely on the fact that 31896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * the first entry is the PHDR because this will not be true 31906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * for certain executables (e.g. some in the NDK unit test suite) 31916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 31926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = 0; 31936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->size = phdr_table_get_load_size(si->phdr, si->phnum); 31946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = 0; 31956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t i = 0; i < si->phnum; ++i) { 31966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->phdr[i].p_type == PT_PHDR) { 31976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr; 31986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset; 31996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 32008180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner } 32016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 32026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->dynamic = nullptr; 32031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 32046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); 32056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (elf_hdr->e_type != ET_DYN) { 32066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n"); 32076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 32086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 32092aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich 32106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). 32116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_LIBRARY_PATH(ldpath_env); 32126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_PRELOAD(ldpreload_env); 32134fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 32146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov somain = si; 32155ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel 32166718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov if (!si->prelink_image()) { 32176718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 32186718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov exit(EXIT_FAILURE); 32196718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov } 322014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 3221d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // add somain to global group 3222d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); 3223d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 32246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Load ld_preloads and dependencies. 32256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov StringLinkedList needed_library_name_list; 32266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t needed_libraries_count = 0; 32276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t ld_preloads_count = 0; 3228d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 3229d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov for (const auto& ld_preload_name : g_ld_preload_names) { 3230d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov needed_library_name_list.push_back(ld_preload_name.c_str()); 32316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 323253ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov ++ld_preloads_count; 32336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 323414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 32356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for_each_dt_needed(si, [&](const char* name) { 32366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.push_back(name); 32376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 32386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov }); 323914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 32406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* needed_library_names[needed_libraries_count]; 324114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 32426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov memset(needed_library_names, 0, sizeof(needed_library_names)); 32436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); 324414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 3245d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (needed_libraries_count > 0 && 3246d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov !find_libraries(si, needed_library_names, needed_libraries_count, nullptr, 3247d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { 32486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 32496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 3250ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else if (needed_libraries_count == 0) { 3251ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) { 3252ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 3253ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov exit(EXIT_FAILURE); 3254ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 3255ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->increment_ref_count(); 32566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 32571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 32586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov add_vdso(args); 3259c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 3260279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov { 3261279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard guard; 32629181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 3263279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov si->call_pre_init_constructors(); 3264279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 3265279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov /* After the prelink_image, the si->load_bias is initialized. 3266279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * For so lib, the map->l_addr will be updated in notify_gdb_of_load. 3267279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * We need to update this value for so exe here. So Unwind_Backtrace 3268279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * for some arch like x86 could work correctly within so exe. 3269279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov */ 3270279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov map->l_addr = si->load_bias; 3271279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov si->call_constructors(); 3272279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 3273e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 32741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING 32756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t1, nullptr); 32766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( 32776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - 32786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); 32791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 32801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 32816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0], 32826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocAbsolute], 32836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocRelative], 32846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocCopy], 32856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocSymbol]); 32861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 32871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 32886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 32896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned n; 32906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned i; 32916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned count = 0; 32926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (n = 0; n < 4096; n++) { 32936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (bitmask[n]) { 32946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned x = bitmask[n]; 3295e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__) 32966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 32; i++) { 3297e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else 32986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 8; i++) { 3299e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif 33006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (x & 1) { 33016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count++; 33026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 33036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov x >>= 1; 33041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 33056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 33061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 33076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4); 33086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 33091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 33101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 33111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES 33126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fflush(stdout); 33131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 33141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3315b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry)); 33166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return si->entry; 33171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3318468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 3319bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only 3320bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library 3321bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself. 3322bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * 3323bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input: 3324bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * elf -> address of ELF header, assumed to be at the start of the file. 3325bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return: 3326bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * load bias, i.e. add the value of any p_vaddr in the file to get 3327bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * the corresponding address in memory. 3328bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */ 33290266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) { 33300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) offset = elf->e_phoff; 3331b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov const ElfW(Phdr)* phdr_table = 3332b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset); 33330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum; 3334fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 33350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) { 3336fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (phdr->p_type == PT_LOAD) { 33370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr; 3338bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner } 3339fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 3340fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return 0; 3341bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner} 3342bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner 3343efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start(); 3344efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 3345468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 3346468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This 3347468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and 3348468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation(). 3349468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * 3350468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own 3351468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern 3352468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault. 3353468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 33540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) { 335542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes KernelArgumentBlock args(raw_args); 335642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 33570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) linker_addr = args.getauxval(AT_BASE); 3358efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); 33590266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); 3360faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); 336142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 3362aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov soinfo linker_so(nullptr, nullptr, 0, 0); 336342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 3364efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // If the linker is not acting as PT_INTERP entry_point is equal to 3365efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // _start. Which means that the linker is running as an executable and 3366efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // already linked by PT_INTERP. 3367efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // 3368efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // This happens when user tries to run 'adb shell /system/bin/linker' 3369efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // see also https://code.google.com/p/android/issues/detail?id=63174 3370efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) { 3371efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]); 3372efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov } 3373efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 337442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.base = linker_addr; 337542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); 337642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); 3377851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov linker_so.dynamic = nullptr; 337842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phdr = phdr; 337942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phnum = elf_hdr->e_phnum; 3380ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov linker_so.set_linker_flag(); 338142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 3382d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // This might not be obvious... The reasons why we pass g_empty_list 3383d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // in place of local_group here are (1) we do not really need it, because 3384d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // linker is built with DT_SYMBOLIC and therefore relocates its symbols against 3385d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // itself without having to look into local_group and (2) allocators 3386d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // are not yet initialized, and therefore we cannot use linked_list.push_* 3387d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // functions at this point. 3388047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) { 338942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // It would be nice to print an error message, but if the linker 339042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // can't link itself, there's no guarantee that we'll be able to 3391b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // call write() (because it involves a GOT reference). We may as 3392b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // well try though... 3393b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes const char* msg = "CANNOT LINK EXECUTABLE: "; 3394b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, msg, strlen(msg)); 3395b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf)); 3396b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, "\n", 1); 3397b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes _exit(EXIT_FAILURE); 339842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes } 3399468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 340014241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov __libc_init_tls(args); 340114241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov 3402efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // Initialize the linker's own global variables 3403047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov linker_so.call_constructors(); 34044151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov 34050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // Initialize static variables. Note that in order to 34060d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // get correct libdl_info we need to call constructors 34070d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // before get_libdl_info(). 34080d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov solist = get_libdl_info(); 34090d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov sonext = get_libdl_info(); 34100d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 341142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // We have successfully fixed our own relocations. It's safe to run 341242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // the main part of the linker now. 34131728b2396591853345507a063ed6075dfd251706Elliott Hughes args.abort_message_ptr = &g_abort_message; 34140266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr); 34155419b9474753d25dff947c7740532f86d130c0beElliott Hughes 3416611f95689e1012283bd11917003d3740d3ce532dElliott Hughes INFO("[ jumping to _start ]"); 3417611f95689e1012283bd11917003d3740d3ce532dElliott Hughes 341842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // Return the address that the calling assembly stub should jump to. 341942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes return start_address; 3420468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich} 3421