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