linker.cpp revision ea6eae182ad64312f80b9adddac511d8938e23e7
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> 384688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h> 391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 400d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new> 410d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 424688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers. 43eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h" 44eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h" 45eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h" 4604dc91ae763adc403a14c88b4c46f77b3d2d71a3Dmitriy Ivanov#include "private/ScopedFd.h" 4714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/ScopeGuard.h" 4814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/UniquePtr.h" 491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h" 511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h" 52be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner#include "linker_environ.h" 5323363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h" 54d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include "linker_allocator.h" 551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<< 571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here. 591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory 601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past. 611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest 621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features 631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo: 651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting 671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY 681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and NOEXEC 694688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes */ 701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 71489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#if defined(__LP64__) 72489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#define SEARCH_NAME(x) x 73489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#else 74489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// Nvidia drivers are relying on the bug: 75489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// http://code.google.com/p/android/issues/detail?id=6670 76489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov// so we continue to use base-name lookup for lp32 77489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanovstatic const char* get_base_name(const char* name) { 78489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov const char* bname = strrchr(name, '/'); 79489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov return bname ? bname + 1 : name; 80489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov} 81489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#define SEARCH_NAME(x) get_base_name(x) 82489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov#endif 83489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov 840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); 851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 861728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic LinkerAllocator<soinfo> g_soinfo_allocator; 87d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic LinkerAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator; 88ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 89d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist; 90d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext; 916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info 921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 931728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = { 944eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__) 95011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes "/vendor/lib64", 96011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes "/system/lib64", 97011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else 98124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes "/vendor/lib", 99124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes "/system/lib", 100011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif 101851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov nullptr 102124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes}; 103124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes 104a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPATH_BUFSIZE (LDPATH_MAX*64) 105a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPATH_MAX 8 106a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 107a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPRELOAD_BUFSIZE (LDPRELOAD_MAX*64) 108a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#define LDPRELOAD_MAX 8 109a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 1101728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic char g_ld_library_paths_buffer[LDPATH_BUFSIZE]; 1111728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* g_ld_library_paths[LDPATH_MAX + 1]; 112bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley 1131728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic char g_ld_preloads_buffer[LDPRELOAD_BUFSIZE]; 1141728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* g_ld_preload_names[LDPRELOAD_MAX + 1]; 1154fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 1161728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic soinfo* g_ld_preloads[LDPRELOAD_MAX + 1]; 1174fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 1181728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity; 1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 120851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd. 1210d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 122bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesenum RelocationKind { 1236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov kRelocAbsolute = 0, 1246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov kRelocRelative, 1256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov kRelocCopy, 1266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov kRelocSymbol, 1276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov kRelocMax 128bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}; 129be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 131bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t { 1326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int count[kRelocMax]; 133bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}; 134bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 135bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats; 136bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 137bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void count_relocation(RelocationKind kind) { 1386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++linker_stats.count[kind]; 139bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 140bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else 141bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void count_relocation(RelocationKind) { 142bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 146bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic unsigned bitmask[4096]; 147e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__) 148e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#define MARK(offset) \ 149e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland do { \ 1506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((((offset) >> 12) >> 5) < 4096) \ 1516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \ 152faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes } while (0) 153e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else 154bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#define MARK(offset) \ 155bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes do { \ 1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \ 157faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes } while (0) 158e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif 159bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else 160bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#define MARK(x) do {} while (0) 1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1634688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// You shouldn't try to call memory-allocating functions in the dynamic linker. 1644688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Guard against the most obvious ones. 1658f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#define DISALLOW_ALLOCATION(return_type, name, ...) \ 1668f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes return_type name __VA_ARGS__ \ 1678f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes { \ 1686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_fatal("ERROR: " #name " called from the dynamic linker!\n"); \ 1694688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes } 170812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, malloc, (size_t u __unused)); 171812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void, free, (void* u __unused)); 172812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, realloc, (void* u1 __unused, size_t u2 __unused)); 173812fd4263a005b88f3b4222baa910114f938d594Kito ChengDISALLOW_ALLOCATION(void*, calloc, (size_t u1 __unused, size_t u2 __unused)); 1742e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 1752e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768]; 1762e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 177650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() { 1785419b9474753d25dff947c7740532f86d130c0beElliott Hughes return &__linker_dl_err_buf[0]; 1792e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin} 1802e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 181650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() { 182650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes return sizeof(__linker_dl_err_buf); 183650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes} 184650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes 1856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified 1866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity. 1875419b9474753d25dff947c7740532f86d130c0beElliott Hughesextern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(); 1881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1891728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER; 190851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanovstatic r_debug _r_debug = {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0}; 1913a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0; 1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1933a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) { 1946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Copy the necessary fields into the debug structure. 1956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(info->link_map_head); 1966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = info->load_bias; 1976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_name = reinterpret_cast<char*>(info->name); 1986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_ld = info->dynamic; 1996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 2006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Stick the new library at the end of the list. 2016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // gdb tends to care more about libc than it does 2026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // about leaf libraries, and ordering it this way 2036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // reduces the back-and-forth over the wire. 2046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (r_debug_tail) { 2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail->l_next = map; 2066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = r_debug_tail; 2076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = 0; 2086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 2096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_map = map; 2106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = 0; 2116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = 0; 2126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map; 2141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 216bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) { 2176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(info->link_map_head); 2185e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (r_debug_tail == map) { 2206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map->l_prev; 2216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2225e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (map->l_prev) { 2246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev->l_next = map->l_next; 2256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (map->l_next) { 2276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next->l_prev = map->l_prev; 2286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2295e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev} 2305e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 231bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) { 2326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (info->flags & FLAG_EXE) { 2336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // GDB already knows about the main executable 2346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ScopedPthreadMutexLocker locker(&g__r_debug_mutex); 2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_ADD; 2406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov insert_soinfo_into_debug_map(info); 2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_CONSISTENT; 2456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2465e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev} 2475e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 248bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) { 2496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (info->flags & FLAG_EXE) { 2506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // GDB already knows about the main executable 2516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 2526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2535e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ScopedPthreadMutexLocker locker(&g__r_debug_mutex); 2555e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_DELETE; 2576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2585e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov remove_soinfo_from_debug_map(info); 2605e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 2616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_state = r_debug::RT_CONSISTENT; 2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rtld_db_dlactivity(); 2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 26518a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() { 2663a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes _r_debug.r_state = r_debug::RT_ADD; 2673a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes rtld_db_dlactivity(); 2683a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes _r_debug.r_state = r_debug::RT_CONSISTENT; 2693a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes rtld_db_dlactivity(); 2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 272d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() { 273d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return g_soinfo_links_allocator.alloc(); 274d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 275d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 276d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) { 277d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov g_soinfo_links_allocator.free(entry); 278d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 279d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 280d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void protect_data(int protection) { 281d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov g_soinfo_allocator.protect_all(protection); 282d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov g_soinfo_links_allocator.protect_all(protection); 283d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 284d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 28507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) { 286ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn if (strlen(name) >= SOINFO_NAME_LEN) { 287ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn DL_ERR("library name \"%s\" too long", name); 288851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 289ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn } 290ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 29107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags); 292d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 293ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext->next = si; 294ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext = si; 2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 296ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("name %s: allocated soinfo @ %p", name, si); 297ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn return si; 2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 300faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) { 3016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 3026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 3036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3044688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 3056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->base != 0 && si->size != 0) { 3066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov munmap(reinterpret_cast<void*>(si->base), si->size); 3076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 308d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo *prev = nullptr, *trav; 3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("name %s: freeing soinfo @ %p", si->name, si); 3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (trav = solist; trav != nullptr; trav = trav->next) { 3146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == si) { 3156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev = trav; 3186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == nullptr) { 3206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // si was not in solist 3216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("name \"%s\" is not in solist!", si->name); 3226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 3236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // clear links to/from si 3266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->remove_all_links(); 327d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // prev will never be null, because the first entry in solist is 3296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // always the static libdl_info. 3306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev->next = si->next; 3316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == sonext) { 3326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sonext = prev; 3336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 334d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov 3356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_soinfo_allocator.free(si); 3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 338cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 339cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_path(const char* path, const char* delimiters, 340cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes const char** array, char* buf, size_t buf_size, size_t max_count) { 341851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (path == nullptr) { 342cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes return; 343cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 344cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 345cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes size_t len = strlcpy(buf, path, buf_size); 346cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 347cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes size_t i = 0; 348cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes char* buf_p = buf; 349cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) { 350cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes if (*array[i] != '\0') { 351cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes ++i; 352cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 353cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 354cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 355cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes // Forget the last path if we had to truncate; this occurs if the 2nd to 356cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes // last char isn't '\0' (i.e. wasn't originally a delimiter). 357cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') { 358851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov array[i - 1] = nullptr; 359cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } else { 360851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov array[i] = nullptr; 361cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 362cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 363cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 364cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_LIBRARY_PATH(const char* path) { 3651728b2396591853345507a063ed6075dfd251706Elliott Hughes parse_path(path, ":", g_ld_library_paths, 3661728b2396591853345507a063ed6075dfd251706Elliott Hughes g_ld_library_paths_buffer, sizeof(g_ld_library_paths_buffer), LDPATH_MAX); 367cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 368cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 369cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_PRELOAD(const char* path) { 370cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes // We have historically supported ':' as well as ' ' in LD_PRELOAD. 3711728b2396591853345507a063ed6075dfd251706Elliott Hughes parse_path(path, " :", g_ld_preload_names, 3721728b2396591853345507a063ed6075dfd251706Elliott Hughes g_ld_preloads_buffer, sizeof(g_ld_preloads_buffer), LDPRELOAD_MAX); 373cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 374cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 3754eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 3764688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 3776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// For a given PC, find the .so that it belongs to. 3786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Returns the base address of the .ARM.exidx section 3796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// for that .so, and the number of 8-byte entries 3806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// in that section (via *pcount). 3816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// 3826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Intended to be called by libc's __gnu_Unwind_Find_exidx(). 3836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// 3846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is exposed via dlfcn.cpp and libdl.so. 385faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { 3866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned addr = (unsigned)pc; 3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (soinfo* si = solist; si != 0; si = si->next) { 3896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((addr >= si->base) && (addr < (si->base + si->size))) { 3906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *pcount = si->ARM_exidx_count; 3916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return (_Unwind_Ptr)si->ARM_exidx; 3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *pcount = 0; 3956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return nullptr; 3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3974688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 39824053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif 3994688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 4006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Here, we only have to provide a callback to iterate across all the 4016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// loaded libraries. gcc_eh does the rest. 402faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesint dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) { 4036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int rv = 0; 4046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 4056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_phdr_info dl_info; 4066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_addr = si->link_map_head.l_addr; 4076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_name = si->link_map_head.l_name; 4086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_phdr = si->phdr; 4096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_phnum = si->phnum; 4106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rv = cb(&dl_info, sizeof(dl_phdr_info), data); 4116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (rv != 0) { 4126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 4156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return rv; 4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4174688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 41802aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanovstatic ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { 4190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Sym)* symtab = si->symtab; 4201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4210266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", 4220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket); 4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4240266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) { 4250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Sym)* s = symtab + n; 4266cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov if (strcmp(si->get_string(s->st_name), name)) continue; 4271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // only concern ourselves with global and weak symbol definitions 4290266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes switch (ELF_ST_BIND(s->st_info)) { 4300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes case STB_GLOBAL: 4310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes case STB_WEAK: 4320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if (s->st_shndx == SHN_UNDEF) { 433d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov continue; 434d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov } 4351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 436d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", 4370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes name, si->name, reinterpret_cast<void*>(s->st_value), 4380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes static_cast<size_t>(s->st_size)); 439d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov return s; 440d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov case STB_LOCAL: 44102aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov continue; 442d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov default: 44312bf3bcdeeaa0dcdc7a4f4e4d11bc2fc3bf6bd7aDmitriy Ivanov __libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'", 44412bf3bcdeeaa0dcdc7a4f4e4d11bc2fc3bf6bd7aDmitriy Ivanov ELF_ST_BIND(s->st_info), name, si->name); 4451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4460266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 4471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 448aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd", 449aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket); 450aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 451aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 452851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 4531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 45507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanovsoinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags) { 4560d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov memset(this, 0, sizeof(*this)); 4570d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 4580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov strlcpy(this->name, name, sizeof(this->name)); 4590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov flags = FLAG_NEW_SOINFO; 4600d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov version = SOINFO_VERSION; 4610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 462851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (file_stat != nullptr) { 46307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov this->st_dev = file_stat->st_dev; 46407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov this->st_ino = file_stat->st_ino; 46507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov this->file_offset = file_offset; 4660d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov } 467e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 468e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov this->rtld_flags = rtld_flags; 4690d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov} 4700d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 471d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstromstatic unsigned elfhash(const char* _name) { 4726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const unsigned char* name = reinterpret_cast<const unsigned char*>(_name); 4736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned h = 0, g; 4746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 4756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov while (*name) { 4766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov h = (h << 4) + *name++; 4776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g = h & 0xf0000000; 4786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov h ^= g; 4796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov h ^= g >> 24; 4806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 4816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return h; 4821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 48429bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovstatic ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { 4856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned elf_hash = elfhash(name); 4866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* s = nullptr; 4876ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 48896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov /* "This element's presence in a shared object library alters the dynamic linker's 48996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * symbol resolution algorithm for references within the library. Instead of starting 49096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * a symbol search with the executable file, the dynamic linker starts from the shared 49196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * object itself. If the shared object fails to supply the referenced symbol, the 49296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * dynamic linker then searches the executable file and other shared objects as usual." 49396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * 49496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html 49596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * 49696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * Note that this is unlikely since static linker avoids generating 49796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * relocations for -Bsymbolic linked dynamic executables. 49896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov */ 49996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (si->has_DT_SYMBOLIC) { 50096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si->name, name); 50196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov s = soinfo_elf_lookup(si, elf_hash, name); 5028f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s != nullptr) { 50396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov *lsi = si; 50496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 50596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 50696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov 50796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (s == nullptr && somain != nullptr) { 50896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov // 1. Look for it in the main executable unless we already did. 50996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (si != somain || !si->has_DT_SYMBOLIC) { 51096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov DEBUG("%s: looking up %s in executable %s", 51196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov si->name, name, somain->name); 51296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov s = soinfo_elf_lookup(somain, elf_hash, name); 51396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (s != nullptr) { 51496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov *lsi = somain; 51596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 5168f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 517c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 5188f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov // 2. Look for it in the ld_preloads 5198f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s == nullptr) { 5206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (int i = 0; g_ld_preloads[i] != NULL; i++) { 5216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); 5226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s != nullptr) { 5238f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov *lsi = g_ld_preloads[i]; 5248f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov break; 5256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5278f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 52896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 529c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 53096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov /* Look for symbols in the local scope (the object who is 53196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * searching). This happens with C++ templates on x86 for some 53296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * reason. 53396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * 53496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * Notes on weak symbols: 53596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * The ELF specs are ambiguous about treatment of weak definitions in 53696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * dynamic linking. Some systems return the first definition found 53796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * and some the first non-weak definition. This is system dependent. 53896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * Here we return the first definition found for simplicity. */ 5396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 54096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (s == nullptr && !si->has_DT_SYMBOLIC) { 54196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov DEBUG("%s: looking up %s in local scope", si->name, name); 54296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov s = soinfo_elf_lookup(si, elf_hash, name); 54396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (s != nullptr) { 54496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov *lsi = si; 5456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 5488f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s == nullptr) { 5498f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov si->get_children().visit([&](soinfo* child) { 5508f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov DEBUG("%s: looking up %s in %s", si->name, name, child->name); 5518f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov s = soinfo_elf_lookup(child, elf_hash, name); 5528f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s != nullptr) { 5538f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov *lsi = child; 5548f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov return false; 5558f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 5568f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov return true; 5578f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov }); 5588f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 5596ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 5606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s != nullptr) { 5616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " 5626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov "found in %s, base = %p, load bias = %p", 5636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->name, name, reinterpret_cast<void*>(s->st_value), 5646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*lsi)->name, reinterpret_cast<void*>((*lsi)->base), 5656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reinterpret_cast<void*>((*lsi)->load_bias)); 5666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 5688f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov return s; 5696ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev} 5706ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 5710cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator. 5720cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 5730cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator { 5740cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 5750cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void* alloc() { 5760cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return allocator_.alloc(); 5770cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 5780cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5790cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(void* ptr) { 5800cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov allocator_.free(ptr); 5810cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 5824bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov 5830cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private: 5840cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static LinkerBlockAllocator allocator_; 5850cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 5860cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5870cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 5880cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size); 5890cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5900cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T> 5910cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator { 5920cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 5930cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static T* alloc() { 5940cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc()); 5950cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 5960cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5970cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(T* ptr) { 5980cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SizeBasedAllocator<sizeof(T)>::free(ptr); 5990cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 6000cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 6010cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 60214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask { 60314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public: 60414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct deleter_t { 60514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov void operator()(LoadTask* t) { 60614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TypeBasedAllocator<LoadTask>::free(t); 60714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 60814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }; 609a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 61014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov typedef UniquePtr<LoadTask, deleter_t> unique_ptr; 611d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom 61214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov static deleter_t deleter; 61314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 61414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov static LoadTask* create(const char* name, soinfo* needed_by) { 61514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc(); 61614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return new (ptr) LoadTask(name, needed_by); 617aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 618a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 61914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* get_name() const { 62014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return name_; 621a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 62214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 62314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* get_needed_by() const { 62414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return needed_by_; 62514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 62614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private: 62714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask(const char* name, soinfo* needed_by) 62814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov : name_(name), needed_by_(needed_by) {} 62914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 63014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name_; 63114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed_by_; 63214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 63314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); 634aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}; 635aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 636e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng JianLoadTask::deleter_t LoadTask::deleter; 637e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian 63814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T> 63914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>; 64014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 64114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList; 64214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList; 64314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<LoadTask> LoadTaskList; 64414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 64514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 646aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov// This is used by dlsym(3). It performs symbol lookup only within the 647aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov// specified soinfo object and its dependencies in breadth first order. 64802aa70589d22fa9b65da43de705d6de2715870c6Dmitriy IvanovElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { 6490cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visit_list; 6500cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visited; 6510cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 652aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov visit_list.push_back(si); 653aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov soinfo* current_soinfo; 654aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov while ((current_soinfo = visit_list.pop_front()) != nullptr) { 655042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov if (visited.contains(current_soinfo)) { 656042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov continue; 657042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov } 658042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov 65902aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name); 660aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 661aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov if (result != nullptr) { 662aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov *found = current_soinfo; 663aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov return result; 664aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 665042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov visited.push_back(current_soinfo); 666aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 667aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov current_soinfo->get_children().for_each([&](soinfo* child) { 668aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov visit_list.push_back(child); 669aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov }); 670aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 671aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 672aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov return nullptr; 6731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 675d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the 676d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom start value is null (for RTLD_DEFAULT), the search starts at the 677d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom beginning of the global solist. Otherwise the search starts at the 678d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom specified soinfo (for RTLD_NEXT). 6796ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */ 68002aa70589d22fa9b65da43de705d6de2715870c6Dmitriy IvanovElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) { 681cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes unsigned elf_hash = elfhash(name); 6821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 683851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (start == nullptr) { 684cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes start = solist; 685cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 6861698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer 687851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov ElfW(Sym)* s = nullptr; 688851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) { 689e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) { 690e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov continue; 691e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 692e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 69302aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov s = soinfo_elf_lookup(si, elf_hash, name); 694851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 695cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes *found = si; 696cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes break; 6971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 698cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 6991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 700851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 701c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p", 702c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base)); 703cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 7041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 705cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes return s; 7061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 708fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) { 7090266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p); 710851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 711fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (address >= si->base && address - si->base < si->size) { 712fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return si; 713e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 714fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 715851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 716e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 717e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 7180266ae5f884d72da58f33a072e865ba131234a5eElliott HughesElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) { 7190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - si->base; 720fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 721fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // Search the library's symbol table for any defined symbol which 722fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // contains this address. 723fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng for (size_t i = 0; i < si->nchain; ++i) { 7240266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Sym)* sym = &si->symtab[i]; 725fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (sym->st_shndx != SHN_UNDEF && 726fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng soaddr >= sym->st_value && 727fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng soaddr < sym->st_value + sym->st_size) { 728fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return sym; 729e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 730fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 731e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 732851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 733e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 734e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 735124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library_on_path(const char* name, const char* const paths[]) { 736124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes char buf[512]; 737851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (size_t i = 0; paths[i] != nullptr; ++i) { 7381e980b6bc8315d00a07312b25486531247abd98cElliott Hughes int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name); 739124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (n < 0 || n >= static_cast<int>(sizeof(buf))) { 740ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name); 741124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes continue; 7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 743124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC)); 744124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (fd != -1) { 745124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return fd; 746124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 747124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 748124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return -1; 7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 751124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library(const char* name) { 752ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ opening %s ]", name); 7531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 754124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes // If the name contains a slash, we should attempt to open it directly and not search the paths. 755851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (strchr(name, '/') != nullptr) { 7566971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC)); 7576971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes if (fd != -1) { 7586971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes return fd; 7596971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes } 7606971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now. 7615ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#if defined(__LP64__) 762e43c4a7a665032a29cb5ec15d4adbf81ea199220Dmitriy Ivanov return -1; 7635ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#endif 764124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 7651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 766124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths. 7671728b2396591853345507a063ed6075dfd251706Elliott Hughes int fd = open_library_on_path(name, g_ld_library_paths); 768124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (fd == -1) { 7691728b2396591853345507a063ed6075dfd251706Elliott Hughes fd = open_library_on_path(name, kDefaultLdPaths); 770124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 771124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return fd; 7721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 77414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F> 77514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) { 77614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { 77714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (d->d_tag == DT_NEEDED) { 7786cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov action(si->get_string(d->d_un.d_val)); 779d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 78014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 78114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 782d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 783e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { 78414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov int fd = -1; 78507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov off64_t file_offset = 0; 78614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov ScopedFd file_guard(-1); 787d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 78814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { 78914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov fd = extinfo->library_fd; 79007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_OFFSET) != 0) { 79107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov file_offset = extinfo->library_offset; 79207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 79314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } else { 79414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Open the file. 79514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov fd = open_library(name); 79614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (fd == -1) { 79714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DL_ERR("library \"%s\" not found", name); 798498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov return nullptr; 799498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov } 800b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 80114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov file_guard.reset(fd); 80214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 80323363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner 80407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((file_offset % PAGE_SIZE) != 0) { 80507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov DL_ERR("file offset for the library %s is not page-aligned: %" PRId64, name, file_offset); 80607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 80707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 80807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 80914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct stat file_stat; 81014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { 81114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); 81214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 81314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 814d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 81514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Check for symlink and other situations where 81614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // file can have different names. 81714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 81814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si->get_st_dev() != 0 && 81914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->get_st_ino() != 0 && 82014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->get_st_dev() == file_stat.st_dev && 82107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov si->get_st_ino() == file_stat.st_ino && 82207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov si->get_file_offset() == file_offset) { 82314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); 82414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 825498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov } 82614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 827d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 828e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if ((rtld_flags & RTLD_NOLOAD) != 0) { 829a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); 83014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 83114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 832a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 83314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Read the ELF header and load the segments. 83407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov ElfReader elf_reader(name, fd, file_offset); 83514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!elf_reader.Load(extinfo)) { 83614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 83714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 838d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 83907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags); 84014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == nullptr) { 84114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 84214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 84314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->base = elf_reader.load_start(); 84414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->size = elf_reader.load_size(); 84514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->load_bias = elf_reader.load_bias(); 84614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->phnum = elf_reader.phdr_count(); 84714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->phdr = elf_reader.loaded_phdr(); 84814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 84914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!si->PrelinkImage()) { 85014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_free(si); 85114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 85214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 853a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 85414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for_each_dt_needed(si, [&] (const char* name) { 85514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.push_back(LoadTask::create(name, si)); 85614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 85714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 85814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 8591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 8601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 861489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanovstatic soinfo *find_loaded_library_by_name(const char* name) { 862489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov const char* search_name = SEARCH_NAME(name); 863851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 864489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov if (!strcmp(search_name, si->name)) { 865489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov return si; 86612c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel } 867489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov } 868851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 86912c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel} 87012c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel 871e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { 872d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 873489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov soinfo* si = find_loaded_library_by_name(name); 874b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 875b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // Library might still be loaded, the accurate detection 87614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // of this fact is done by load_library. 877851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (si == nullptr) { 878b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov TRACE("[ '%s' has not been found by name. Trying harder...]", name); 879e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov si = load_library(load_tasks, name, rtld_flags, extinfo); 880b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov } 881b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 88214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 88314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 88414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 88514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si); 88614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 88714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic bool is_recursive(soinfo* si, soinfo* parent) { 88814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (parent == nullptr) { 88914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 89014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 89114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 89214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == parent) { 893b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov DL_ERR("recursive link to \"%s\"", si->name); 89414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return true; 895d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 896a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 89714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return !parent->get_parents().visit([&](soinfo* grandparent) { 89814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return !is_recursive(si, grandparent); 89914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 900a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov} 901a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 90214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], 903e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { 90414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 0: prepare. 90514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTaskList load_tasks; 90614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (size_t i = 0; i < library_names_size; ++i) { 90714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name = library_names[i]; 90814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.push_back(LoadTask::create(name, nullptr)); 90914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 91014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 91114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Libraries added to this list in reverse order so that we can 91214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // start linking from bottom-up - see step 2. 91314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov SoinfoLinkedList found_libs; 91414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov size_t soinfos_size = 0; 91514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 916d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov auto failure_guard = make_scope_guard([&]() { 91714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Housekeeping 91814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.for_each([] (LoadTask* t) { 91914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask::deleter(t); 92014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 92114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 92214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (size_t i = 0; i<soinfos_size; ++i) { 92314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_unload(soinfos[i]); 92414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 92514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 92614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 92714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order. 92814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) { 929e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo); 93014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == nullptr) { 93114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 93214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 93314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 93414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed_by = task->get_needed_by(); 93514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 93614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (is_recursive(si, needed_by)) { 93714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 93814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 93914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 940498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov si->ref_count++; 94114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (needed_by != nullptr) { 94214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov needed_by->add_child(si); 94314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 94414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov found_libs.push_front(si); 94514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 94614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // When ld_preloads is not null first 94714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // ld_preloads_size libs are in fact ld_preloads. 94814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { 94914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov ld_preloads[soinfos_size] = si; 95014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 95114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 95214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (soinfos_size<library_names_size) { 95314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfos[soinfos_size++] = si; 95414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 95514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 95614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 95714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 2: link libraries. 95814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* si; 95914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov while ((si = found_libs.pop_front()) != nullptr) { 96014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if ((si->flags & FLAG_LINKED) == 0) { 96114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!si->LinkImage(extinfo)) { 96214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 96314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 96414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->flags |= FLAG_LINKED; 96514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 966a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 96714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 96814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // All is well - found_libs and load_tasks are empty at this point 96914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // and all libs are successfully linked. 97014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov failure_guard.disable(); 97114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return true; 97214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 97314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 974e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { 97514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (name == nullptr) { 97614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov somain->ref_count++; 97714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return somain; 97814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 97914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 98014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* si; 98114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 982e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { 98314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 98414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 98514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 986d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return si; 987d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 988d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 989b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovstatic void soinfo_unload(soinfo* si) { 9901b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov if (!si->can_unload()) { 9911b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->name); 9921b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov return; 9931b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov } 9941b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov 995ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes if (si->ref_count == 1) { 996ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("unloading '%s'", si->name); 997d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes si->CallDestructors(); 998d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 9990d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (si->has_min_version(0)) { 100014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* child = nullptr; 100114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov while ((child = si->get_children().pop_front()) != nullptr) { 100214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TRACE("%s needs to unload %s", si->name, child->name); 100314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_unload(child); 10044bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov } 1005d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } else { 100614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for_each_dt_needed(si, [&] (const char* library_name) { 100714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name); 100814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); 100914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (needed != nullptr) { 101014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_unload(needed); 101114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } else { 101214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Not found: for example if symlink was deleted between dlopen and dlclose 101314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Since we cannot really handle errors at this point - print and continue. 101414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); 1015d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 101614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 10171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 10181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1019d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes notify_gdb_of_unload(si); 1020ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes si->ref_count = 0; 1021d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov soinfo_free(si); 1022d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } else { 1023ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes si->ref_count--; 1024c620059479c47a78d57086d73726c9adc2f337adElliott Hughes TRACE("not unloading '%s', decrementing ref_count to %zd", si->name, si->ref_count); 1025d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 10261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 10271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1028a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) { 1029052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Use basic string manipulation calls to avoid snprintf. 1030052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf indirectly calls pthread_getspecific to get the size of a buffer. 1031052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // When debug malloc is enabled, this call returns 0. This in turn causes 1032052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf to do nothing, which causes libraries to fail to load. 1033052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // See b/17302493 for further details. 1034052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Once the above bug is fixed, this code can be modified to use 1035052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf again. 1036052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2; 1037052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris if (buffer_size < required_len) { 1038052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: buffer len %zu, required len %zu", 1039052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris buffer_size, required_len); 1040052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris } 1041052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris char* end = stpcpy(buffer, kDefaultLdPaths[0]); 1042052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris *end = ':'; 1043052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris strcpy(end + 1, kDefaultLdPaths[1]); 1044a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes} 1045a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 1046cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { 1047cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes if (!get_AT_SECURE()) { 1048cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes parse_LD_LIBRARY_PATH(ld_library_path); 1049cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 1050cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 1051cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 10521a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughessoinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { 10531b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) { 1054e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes DL_ERR("invalid flags to dlopen: %x", flags); 1055851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1056e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes } 105707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if (extinfo != nullptr) { 105807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) { 105907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags); 106007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 106107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 106207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 && 106307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_OFFSET) != 0) { 106407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags); 106507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 106607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 1067012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles) } 1068d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 1069b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov soinfo* si = find_library(name, flags, extinfo); 1070851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (si != nullptr) { 1071d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes si->CallConstructors(); 1072d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1073d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ); 1074d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return si; 1075d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 10761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1077b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid do_dlclose(soinfo* si) { 1078d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 1079b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov soinfo_unload(si); 1080d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ); 10811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 10821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 10839aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { 10849aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov typedef ElfW(Addr) (*ifunc_resolver_t)(void); 10859aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr); 10869aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ElfW(Addr) ifunc_addr = ifunc_resolver(); 10879aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", ifunc_resolver, reinterpret_cast<void*>(ifunc_addr)); 1088c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 10899aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return ifunc_addr; 1090c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith} 1091c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 10924eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 109329bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovint soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { 1094c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes for (size_t idx = 0; idx < count; ++idx, ++rela) { 10950266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes unsigned type = ELFW(R_TYPE)(rela->r_info); 10960266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes unsigned sym = ELFW(R_SYM)(rela->r_info); 109729bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + load_bias); 10980266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) sym_addr = 0; 1099851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov const char* sym_name = nullptr; 1100c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 110129bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov DEBUG("Processing '%s' relocation at index %zd", name, idx); 1102c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (type == 0) { // R_*_NONE 1103c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes continue; 1104c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 110514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 110614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov ElfW(Sym)* s = nullptr; 110714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* lsi = nullptr; 110814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1109c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (sym != 0) { 11106cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov sym_name = get_string(symtab[sym].st_name); 111129bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov s = soinfo_do_lookup(this, sym_name, &lsi); 1112851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s == nullptr) { 1113c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes // We only allow an undefined symbol if this is a weak reference... 111429bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov s = &symtab[sym]; 1115c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 111629bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); 1117c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes return -1; 1118c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1119c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1120c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes /* IHI0044C AAELF 4.5.1.1: 1121c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1122c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes Libraries are not searched to resolve weak references. 1123c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes It is not an error for a weak reference to remain unsatisfied. 1124c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1125c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes During linking, the value of an undefined weak reference is: 1126c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - Zero if the relocation type is absolute 1127c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of the place if the relocation is pc-relative 1128c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of nominal base address if the relocation 1129c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes type is base-relative. 1130c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes */ 1131c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1132c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 1133e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__) 11346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_JUMP_SLOT: 11356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_GLOB_DAT: 11366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 11376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 11386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 11396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_RELATIVE: 11406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_IRELATIVE: 11416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 11426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * The sym_addr was initialized to be zero above, or the relocation 11436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * code below does not care about value of sym_addr. 11446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * No need to do anything. 11456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 11466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1147e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__) 11486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_JUMP_SLOT: 11496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_GLOB_DAT: 11506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_32: 11516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_64: 11526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_RELATIVE: 11536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_IRELATIVE: 11546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // No need to do anything. 11556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 11566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_PC32: 11576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sym_addr = reloc; 11586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 11594eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 11606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 11616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rela, idx); 11626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1163c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1164c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } else { 1165c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes // We got a definition. 11669aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 1167c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1168c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes count_relocation(kRelocSymbol); 1169c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1170c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1171c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 1172e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__) 11736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_JUMP_SLOT: 1174e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1175e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11760266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO JMP_SLOT %16llx <- %16llx %s\n", 11770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11780266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend); 1179e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_GLOB_DAT: 1181e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1182e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11830266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO GLOB_DAT %16llx <- %16llx %s\n", 11840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11850266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend); 1186e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 1188e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1189e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11900266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n", 11910266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11920266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend); 1193e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 1195e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1196e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11970266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n", 11980266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11990266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) && 12000266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) { 12016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend); 1202e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 12036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 12046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)), 12056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT32_MIN), 12066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT32_MAX)); 12076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1208e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1209e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 12106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 1211e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1212e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 12130266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n", 12140266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 12150266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) && 12160266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) { 12176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend); 1218e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 12196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 12206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)), 12216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT16_MIN), 12226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT16_MAX)); 12236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1224e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1225e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 12266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL64: 1227e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1228e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 12290266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n", 12300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); 12310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend) - rela->r_offset; 1232e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 12336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL32: 1234e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1235e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 12360266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n", 12370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); 12380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && 12390266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) { 12406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); 1241e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 12426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 12436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), 12446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT32_MIN), 12456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT32_MAX)); 12466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1247e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1248e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 12496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL16: 1250e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1251e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 12520266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n", 12530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); 12540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && 12550266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) { 12566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); 1257e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 12586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 12596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), 12606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT16_MIN), 12616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT16_MAX)); 12626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1263e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1264e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1265e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 12666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_RELATIVE: 1267e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1268e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 1269e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland if (sym) { 12706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("odd RELATIVE form..."); 12716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1272e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 12730266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n", 127429bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov reloc, (base + rela->r_addend)); 127529bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (base + rela->r_addend); 1276e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1277e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 12786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_IRELATIVE: 12796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 12806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 12816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); 12826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + rela->r_addend); 12836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 12849aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 12856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_COPY: 128676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich /* 128776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * ET_EXEC is not supported so this should not happen. 128876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 128976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 129076e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 129176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * Section 4.7.1.10 "Dynamic relocations" 129276e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * R_AARCH64_COPY may only appear in executable objects where e_type is 129376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * set to ET_EXEC. 129476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich */ 129529bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov DL_ERR("%s R_AARCH64_COPY relocations are not supported", name); 129676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich return -1; 12976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_TPREL64: 12980266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", 12990266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset); 1300e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 13016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_DTPREL32: 13020266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n", 13030266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset); 1304e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1305e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__) 13066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_JUMP_SLOT: 13076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 13086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast<size_t>(reloc), 13106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr + rela->r_addend), sym_name); 13116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 13126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_GLOB_DAT: 13146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 13156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %08zx <- %08zx %s", static_cast<size_t>(reloc), 13176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr + rela->r_addend), sym_name); 13186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 13196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_RELATIVE: 13216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 13226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (sym) { 13246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("odd RELATIVE form..."); 13256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 13266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 13276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast<size_t>(reloc), 13286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(base)); 13296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = base + rela->r_addend; 13306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_IRELATIVE: 13326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 13336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); 13356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + rela->r_addend); 13366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_32: 13386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 13396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 13416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 13426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 13436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_64: 13456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 13466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 13486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 13496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 13506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_PC32: 13526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 13536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", 13556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc), 13566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name); 13576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend - reloc; 13586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13594eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 1360e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 13616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 13626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rela, idx); 13636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1364c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1365c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1366c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes return 0; 1367c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes} 13689918665a45095ad135576f005c0e5307feb366a1Chris Dearman 13699918665a45095ad135576f005c0e5307feb366a1Chris Dearman#else // REL, not RELA. 137029bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovint soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { 13716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t idx = 0; idx < count; ++idx, ++rel) { 13726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned type = ELFW(R_TYPE)(rel->r_info); 13736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. 13746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned sym = ELFW(R_SYM)(rel->r_info); 13756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias); 13766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Addr) sym_addr = 0; 13776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* sym_name = nullptr; 13786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("Processing '%s' relocation at index %zd", name, idx); 13806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (type == 0) { // R_*_NONE 13816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 13826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 13836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* s = nullptr; 13856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo* lsi = nullptr; 13866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (sym != 0) { 13886cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov sym_name = get_string(symtab[sym].st_name); 13896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = soinfo_do_lookup(this, sym_name, &lsi); 13906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s == nullptr) { 13916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We only allow an undefined symbol if this is a weak reference... 13926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = &symtab[sym]; 13936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 13946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); 13956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1396d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 139714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 13986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* IHI0044C AAELF 4.5.1.1: 13996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 14006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov Libraries are not searched to resolve weak references. 14016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov It is not an error for a weak reference to remain 14026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsatisfied. 14036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 14046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov During linking, the value of an undefined weak reference is: 14056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov - Zero if the relocation type is absolute 14066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov - The address of the place if the relocation is pc-relative 14076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov - The address of nominal base address if the relocation 14086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov type is base-relative. 14096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 14106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 14116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (type) { 14124eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 14136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_JUMP_SLOT: 14146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_GLOB_DAT: 14156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_ABS32: 14166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_RELATIVE: /* Don't care. */ 14176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // sym_addr was initialized to be zero above or relocation 14186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // code below does not care about value of sym_addr. 14196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // No need to do anything. 14206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14214eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 14226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_JMP_SLOT: 14236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_GLOB_DAT: 14246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_32: 14256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_RELATIVE: /* Don't care. */ 14266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_IRELATIVE: 14276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // sym_addr was initialized to be zero above or relocation 14286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // code below does not care about value of sym_addr. 14296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // No need to do anything. 14306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_PC32: 14326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sym_addr = reloc; 14336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14344eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 1435e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan 14364eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 14376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_COPY: 14386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Fall through. Can't really copy if weak symbol is not found at run-time. 14394eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 14406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 14416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx); 14426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 14431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 14446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 14456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We got a definition. 14466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 14476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 14486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocSymbol); 14496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 14501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 14516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (type) { 14524eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 14536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_JUMP_SLOT: 14546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); 14576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 14586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_GLOB_DAT: 14606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); 14636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 14646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_ABS32: 14666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name); 14696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 14706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_REL32: 14726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 14736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s", 14756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, sym_addr, rel->r_offset, sym_name); 14766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset; 14776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_COPY: 14796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 14806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * ET_EXEC is not supported so this should not happen. 14816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 14826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 14836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 14846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * Section 4.7.1.10 "Dynamic relocations" 14856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * R_ARM_COPY may only appear in executable objects where e_type is 14866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * set to ET_EXEC. 14876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 14886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("%s R_ARM_COPY relocations are not supported", name); 14896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 14904eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 14916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_JMP_SLOT: 14926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); 14956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 14966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_GLOB_DAT: 14986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); 15016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 15026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_32: 15046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 15056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); 15076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 15086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_PC32: 15106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 15116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", 15136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); 15146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc); 15156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15164eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__mips__) 15176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_MIPS_REL32: 15189918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if defined(__LP64__) 15196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // MIPS Elf64_Rel entries contain compound relocations 15206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case 15216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 || 15226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) { 15236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)", 15246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov type, (unsigned)ELF64_R_TYPE2(rel->r_info), 15256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx); 15266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 15276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15289918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif 15296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 15306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc), 15326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*"); 15336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s) { 15346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 15356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 15366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += base; 15376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15394eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 15404eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes 15414eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 15426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_RELATIVE: 15434eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 15446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_RELATIVE: 15454eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 15466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 15476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (sym) { 15496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("odd RELATIVE form..."); 15506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 15516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p", 15536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base)); 15546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += base; 15556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15569aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#if defined(__i386__) 15576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_IRELATIVE: 15586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 15596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base)); 15616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + *reinterpret_cast<ElfW(Addr)*>(reloc)); 15626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15639aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif 15641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 15656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 15666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); 15676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 15681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 15696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return 0; 15711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1572c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 15731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 15744eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 157529bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovstatic bool mips_relocate_got(soinfo* si) { 15766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Addr)** got = si->plt_got; 15776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (got == nullptr) { 15786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 15796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned local_gotno = si->mips_local_gotno; 15816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned gotsym = si->mips_gotsym; 15826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned symtabno = si->mips_symtabno; 15836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* symtab = si->symtab; 15846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 15856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // got[0] is the address of the lazy resolver function. 15866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // got[1] may be used for a GNU extension. 15876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set it to a recognizable address in case someone calls it (should be _rtld_bind_start). 15886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // FIXME: maybe this should be in a separate routine? 15896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((si->flags & FLAG_LINKER) == 0) { 15906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t g = 0; 15916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadbeef); 15926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (reinterpret_cast<intptr_t>(got[g]) < 0) { 15936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadfeed); 159487c358524e479235aa6241736d2ce325f89daafcBrian Carlstrom } 15956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Relocate the local GOT entries. 15966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (; g < local_gotno; g++) { 15976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got[g] = reinterpret_cast<ElfW(Addr)*>(reinterpret_cast<uintptr_t>(got[g]) + si->load_bias); 1598d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 15996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1600d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 16016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Now for the global GOT entries... 16026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* sym = symtab + gotsym; 16036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got = si->plt_got + local_gotno; 16046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { 16056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // This is an undefined reference... try to locate it. 16066cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov const char* sym_name = si->get_string(sym->st_name); 16076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo* lsi = nullptr; 16086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); 16096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s == nullptr) { 16106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We only allow an undefined symbol if this is a weak reference. 16116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = &symtab[g]; 16126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 16136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("cannot locate \"%s\"...", sym_name); 16146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 16156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 16166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *got = 0; 16176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 16186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // FIXME: is this sufficient? 16196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // For reference see NetBSD link loader 16206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy 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 16216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *got = reinterpret_cast<ElfW(Addr)*>(lsi->resolve_symbol_address(s)); 1622d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 16236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 16246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 1625d7daacb46372132ae3f0121647074936c304b572Raghu Gandham} 1626d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif 1627d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 1628812fd4263a005b88f3b4222baa910114f938d594Kito Chengvoid soinfo::CallArray(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) { 1629851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (functions == nullptr) { 1630d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 1631d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 16328215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1633c620059479c47a78d57086d73726c9adc2f337adElliott Hughes TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, name); 16348215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1635ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int begin = reverse ? (count - 1) : 0; 1636ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int end = reverse ? -1 : count; 1637ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int step = reverse ? -1 : 1; 16388215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1639ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes for (int i = begin; i != end; i += step) { 1640ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]); 1641ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes CallFunction("function", functions[i]); 1642d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1643d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1644ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ Done calling %s for '%s' ]", array_name, name); 16451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1647812fd4263a005b88f3b4222baa910114f938d594Kito Chengvoid soinfo::CallFunction(const char* function_name __unused, linker_function_t function) { 1648851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) { 1649d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 1650d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1651d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1652ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, name); 1653d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes function(); 1654ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, name); 1655db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes 1656db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes // The function may have called dlopen(3) or dlclose(3), so we need to ensure our data structures 1657db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes // are still writable. This happens with our debug malloc (see http://b/7941716). 1658d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 16599181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov} 16609181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 1661d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallPreInitConstructors() { 16628147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_PREINIT_ARRAY functions are called before any other constructors for executables, 16638147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // but ignored in a shared library. 1664d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallArray("DT_PREINIT_ARRAY", preinit_array, preinit_array_count, false); 1665d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 1666e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 1667d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallConstructors() { 1668d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes if (constructors_called) { 1669d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 1670d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1671e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 1672d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // We set constructors_called before actually calling the constructors, otherwise it doesn't 1673d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // protect against recursive constructor calls. One simple example of constructor recursion 1674d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so: 1675d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 1. The program depends on libc, so libc's constructor is called here. 1676d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so. 1677d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 3. dlopen() calls the constructors on the newly created 1678d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // soinfo for libc_malloc_debug_leak.so. 1679d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 4. The debug .so depends on libc, so CallConstructors is 1680d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // called again with the libc soinfo. If it doesn't trigger the early- 1681d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // out above, the libc constructor will be called again (recursively!). 1682d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes constructors_called = true; 1683d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1684851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) { 16858147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // The GNU dynamic linker silently ignores these, but we warn the developer. 1686c620059479c47a78d57086d73726c9adc2f337adElliott Hughes PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!", 16878147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes name, preinit_array_count); 1688d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 16891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1690d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov get_children().for_each([] (soinfo* si) { 1691d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov si->CallConstructors(); 1692d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 16931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 16948147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes TRACE("\"%s\": calling constructors", name); 16958147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 16968147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_INIT should be called before DT_INIT_ARRAY if both are present. 1697d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallFunction("DT_INIT", init_func); 1698d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallArray("DT_INIT_ARRAY", init_array, init_array_count, false); 1699e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov} 17008215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1701d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallDestructors() { 170214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!constructors_called) { 170314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return; 170414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 17058147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes TRACE("\"%s\": calling destructors", name); 17068147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 17078147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI_ARRAY must be parsed in reverse order. 1708d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallArray("DT_FINI_ARRAY", fini_array, fini_array_count, true); 17098147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 17108147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI should be called after DT_FINI_ARRAY if both are present. 1711d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallFunction("DT_FINI", fini_func); 1712b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 1713b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // This is needed on second call to dlopen 1714b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // after library has been unloaded with RTLD_NODELETE 1715b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov constructors_called = false; 17161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 17171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1718d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) { 17190d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 1720b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov child->parents.push_back(this); 1721b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov this->children.push_back(child); 1722d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1723d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1724d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1725d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() { 17260d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (!has_min_version(0)) { 1727d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return; 1728d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1729d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1730d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 1. Untie connected soinfos from 'this'. 1731d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov children.for_each([&] (soinfo* child) { 1732d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov child->parents.remove_if([&] (const soinfo* parent) { 1733d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return parent == this; 1734d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1735d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1736d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1737d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov parents.for_each([&] (soinfo* parent) { 17384bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov parent->children.remove_if([&] (const soinfo* child) { 1739d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return child == this; 1740d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1741d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1742d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1743d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 2. Once everything untied - clear local lists. 1744d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov parents.clear(); 1745d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov children.clear(); 1746d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1747d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1748d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovdev_t soinfo::get_st_dev() { 17490d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17500d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return st_dev; 1751d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1752d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 17530d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 1754d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}; 1755d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1756d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovino_t soinfo::get_st_ino() { 17570d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return st_ino; 1759d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1760d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 17610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 1762d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1763d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 176407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanovoff64_t soinfo::get_file_offset() { 176507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if (has_min_version(1)) { 176607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return file_offset; 176707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 176807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 176907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return 0; 177007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov} 177107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 1772e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovint soinfo::get_rtld_flags() { 1773e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (has_min_version(1)) { 1774e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov return rtld_flags; 1775e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 1776e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 1777e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov return 0; 1778e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov} 1779e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 178014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if 1781d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set. 1782d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list; 1783d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1784d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() { 17850d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17860d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return this->children; 1787d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1788d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 17890d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return g_empty_list; 1790d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1791d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 179214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() { 179314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if ((this->flags & FLAG_NEW_SOINFO) == 0) { 179414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return g_empty_list; 179514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 179614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 179714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return this->parents; 179814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 179914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 18009aea164457c269c475592da36b4655d45f55c7bcDmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) { 18019aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { 18029aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return call_ifunc_resolver(s->st_value + load_bias); 18039aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov } 18049aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 18059aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return static_cast<ElfW(Addr)>(s->st_value + load_bias); 18069aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov} 18079aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 18086cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const { 18096cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov if (has_min_version(1) && (index >= strtab_size)) { 18106cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", name, strtab_size, index); 18116cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 18126cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 18136cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov return strtab + index; 18146cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov} 18156cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 18161b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const { 18171b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov return (rtld_flags & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; 18181b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov} 18191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with 18201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /dev/null. */ 18215419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic int nullify_closed_stdio() { 18226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int dev_null, i, status; 18236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int return_value = 0; 18241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); 18266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dev_null < 0) { 18276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("cannot open /dev/null: %s", strerror(errno)); 18286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 18296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null); 18316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 18326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If any of the stdio file descriptors is valid and not associated 18336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov with /dev/null, dup /dev/null to it. */ 18346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 3; i++) { 18356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If it is /dev/null already, we are done. */ 18366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (i == dev_null) { 18376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 18381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 18391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Nullifying stdio file descriptor %d]", i); 18416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL)); 18421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If file is opened, we are good. */ 18446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (status != -1) { 18456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 18466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* The only error we allow is that the file descriptor does not 18496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exist, in which case we dup /dev/null to it. */ 18506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (errno != EBADF) { 18516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("fcntl failed: %s", strerror(errno)); 18526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return_value = -1; 18536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 18546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Try dupping /dev/null to this stdio file descriptor and 18576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov repeat if there is a signal. Note that any errors in closing 18586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov the stdio descriptor are lost. */ 18596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov status = TEMP_FAILURE_RETRY(dup2(dev_null, i)); 18606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (status < 0) { 18616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("dup2 failed: %s", strerror(errno)); 18626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return_value = -1; 18636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 18641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 18656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If /dev/null is not one of the stdio file descriptors, close it. */ 18686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dev_null > 2) { 18696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null); 18706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov status = TEMP_FAILURE_RETRY(close(dev_null)); 18716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (status == -1) { 18726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("close failed: %s", strerror(errno)); 18736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return_value = -1; 18741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 18756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return return_value; 18781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 188014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovbool soinfo::PrelinkImage() { 1881e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian /* Extract dynamic section */ 1882e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian ElfW(Word) dynamic_flags = 0; 1883e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags); 1884498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov 18856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can't log anything until the linker is relocated */ 18866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov bool relocating_linker = (flags & FLAG_LINKER) != 0; 18876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 18886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov INFO("[ linking %s ]", name); 18896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags); 18906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 18926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dynamic == nullptr) { 1893b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner if (!relocating_linker) { 18946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("missing PT_DYNAMIC in \"%s\"", name); 1895b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner } 18966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 18976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 18986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 18996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("dynamic = %p", dynamic); 190063f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner } 19016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 190263f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 19034eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 19046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, 19056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov &ARM_exidx, &ARM_exidx_count); 190663f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif 190763f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 19086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract useful information from dynamic section. 19096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov uint32_t needed_count = 0; 19106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 19116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", 19126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 19136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (d->d_tag) { 19144a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SONAME: 19154a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // TODO: glibc dynamic linker uses this name for 19164a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // initial library lookup; consider doing the same here. 19174a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 1918ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_HASH: 19206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 19216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 19226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8); 19236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); 19246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1925ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_STRTAB: 19276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr); 19286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1929ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19306cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_STRSZ: 19316cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov strtab_size = d->d_un.d_val; 19326cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 1933ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMTAB: 19356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr); 19366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1937ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19384a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SYMENT: 19394a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Sym))) { 1940f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_SYMENT: %zd", static_cast<size_t>(d->d_un.d_val)); 19414a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 19424a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 19434a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 1944ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTREL: 1946513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA) 1947513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov if (d->d_un.d_val != DT_RELA) { 1948513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", name); 1949513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov return false; 1950513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov } 1951513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else 19526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val != DT_REL) { 1953513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", name); 19546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 19556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1956c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 1957513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 1958ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_JMPREL: 19604eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 19616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 1962c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 19636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 1964c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 19656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1966ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTRELSZ: 19684eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 19696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); 1970c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 19716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); 1972c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 19736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1974ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTGOT: 19764a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__) 19776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Used by mips and mips64. 19786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_got = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr); 1979c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 19804a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // Ignore for other platforms... (because RTLD_LAZY is not supported) 19814a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 1982ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 19836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_DEBUG: 19846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_DEBUG entry to the address of _r_debug for GDB 19856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // if the dynamic table is writable 19869918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64 19879918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree. 198814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as 19899918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable. 19909918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__)) 19916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((dynamic_flags & PF_W) != 0) { 19926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug); 19936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 19946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19959918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif 19964eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 19976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 19986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 19996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2000ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELASZ: 20026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); 20036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2004ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20054a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELAENT: 20064a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rela))) { 2007f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val)); 20084a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 20094a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 20104a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2011ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2012ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // ignored (see DT_RELCOUNT comments for details) 20134a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELACOUNT: 20144a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2015ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 20176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unsupported DT_REL in \"%s\"", name); 20186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2019ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 20216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unsupported DT_RELSZ in \"%s\"", name); 20226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2023c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 20246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 20256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 20266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2027ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 20296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); 20306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2031ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20324a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELENT: 20334a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rel))) { 2034f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val)); 20354a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 20364a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 20374a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 2038ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2039ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // "Indicates that all RELATIVE relocations have been concatenated together, 2040ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // and specifies the RELATIVE relocation count." 2041ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // 2042ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // TODO: Spec also mentions that this can be used to optimize relocation process; 2043ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Not currently used by bionic linker - ignored. 20444a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELCOUNT: 20454a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 20466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 20476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unsupported DT_RELA in \"%s\"", name); 20486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2049c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 20506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT: 20516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 20526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s constructors (DT_INIT) found at %p", name, init_func); 20536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2054ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI: 20566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fini_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 20576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func); 20586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2059ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAY: 20616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 20626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array); 20636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2064ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAYSZ: 20666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); 20676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2068ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAY: 20706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fini_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 20716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array); 20726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2073ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAYSZ: 20756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); 20766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2077ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAY: 20796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov preinit_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 20806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array); 20816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2082ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAYSZ: 20846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); 20856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2086ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_TEXTREL: 2088e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__) 20896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name); 20906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2091e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else 20926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov has_text_relocations = true; 20936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2094e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 2095ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 20966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMBOLIC: 209796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 20986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2099ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 21006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_NEEDED: 21016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_count; 21026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2103ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 21046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FLAGS: 21056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val & DF_TEXTREL) { 2106e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__) 21076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name); 21086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2109e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else 21106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov has_text_relocations = true; 2111e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 21126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 211396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (d->d_un.d_val & DF_SYMBOLIC) { 211496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 211596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 21166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2117ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 21186cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_FLAGS_1: 21196cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { 21206cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov rtld_flags |= RTLD_GLOBAL; 21216cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 21221b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov 21231b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov if ((d->d_un.d_val & DF_1_NODELETE) != 0) { 21241b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov rtld_flags |= RTLD_NODELETE; 21251b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov } 21266cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov // TODO: Implement other flags 21276cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 21281b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)) != 0) { 21296cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val)); 21306cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 21316cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 21324eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 21336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_MAP: 21346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. 21356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 21366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr); 21376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *dp = &_r_debug; 21386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2140ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 21416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_VERSION: 21426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_FLAGS: 21436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_BASE_ADDRESS: 21446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_UNREFEXTNO: 21456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2146d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 21476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_SYMTABNO: 21486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov mips_symtabno = d->d_un.d_val; 21496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2150d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 21516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_LOCAL_GOTNO: 21526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov mips_local_gotno = d->d_un.d_val; 21536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2154d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 21556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_GOTSYM: 21566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov mips_gotsym = d->d_un.d_val; 21576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21584eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 2159ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Ignored: "Its use has been superseded by the DF_BIND_NOW flag" 2160ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov case DT_BIND_NOW: 2161ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov break; 2162ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 2163ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Ignore: bionic does not support symbol versioning... 2164513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERSYM: 2165513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEF: 2166513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEFNUM: 2167513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 2168d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 21696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 21708f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (!relocating_linker) { 21716cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov DL_WARN("%s: unused DT entry: type %p arg %p", name, 21728f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 21738f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 21746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 21751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 21766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", 21796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reinterpret_cast<void*>(base), strtab, symtab); 21801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Sanity checks. 21826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (relocating_linker && needed_count != 0) { 21836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); 21846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (nbucket == 0) { 21876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name); 21886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (strtab == 0) { 21916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("empty/missing DT_STRTAB in \"%s\"", name); 21926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (symtab == 0) { 21956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); 21966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 219914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 22001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 220114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovbool soinfo::LinkImage(const android_dlextinfo* extinfo) { 22021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2203e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__) 22046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (has_text_relocations) { 22056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Make segments writable to allow text relocations to work properly. We will later call 22066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // phdr_table_protect_segments() after all of them are applied and all constructors are run. 22076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_WARN("%s has text relocations. This is wasting memory and prevents " 22086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov "security hardening. Please fix.", name); 22096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 22106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 22116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 22126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 22135135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich } 22146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2215e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 22165135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich 22174eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 22186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (rela != nullptr) { 22196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s ]", name); 22206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(rela, rela_count)) { 22216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2222c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 22236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (plt_rela != nullptr) { 22256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s plt ]", name); 22266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(plt_rela, plt_rela_count)) { 22276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 22281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 22296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22309aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else 22316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (rel != nullptr) { 22326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s ]", name); 22336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(rel, rel_count)) { 22346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 22351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 22366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (plt_rel != nullptr) { 22386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s plt ]", name); 22396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(plt_rel, plt_rel_count)) { 22406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2241c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith } 22426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22439aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif 2244c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 22454eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 22466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!mips_relocate_got(this)) { 22476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 22486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2249d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif 2250d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 22516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ finished linking %s ]", name); 22521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2253e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__) 22546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (has_text_relocations) { 22556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // All relocations are done, we can protect our segments back to read-only. 22566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 22576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't protect segments for \"%s\": %s", 22586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 22596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 22601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 22616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2262e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 22631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can also turn on GNU RELRO protection */ 22656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { 22666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", 22676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 22686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 22696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22709ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich 22716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Handle serializing/sharing the RELRO segment */ 22726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { 22736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, 22746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 22756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", 22766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 22776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2278183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) } 22796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { 22806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, 22816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 22826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", 22836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 22846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 22856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2287183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) 22886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov notify_gdb_of_load(this); 22896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 22901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 22911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2292468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 2293c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list. 2294c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers. 2295c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc. 2296c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */ 2297812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) { 22984eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR) 22990266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR)); 2300851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (ehdr_vdso == nullptr) { 23010266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return; 23020266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 2303c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 230407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0); 2305ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 23060266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff); 23070266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phnum = ehdr_vdso->e_phnum; 23080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso); 23090266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->size = phdr_table_get_load_size(si->phdr, si->phnum); 23100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->load_bias = get_elf_exec_load_bias(ehdr_vdso); 2311ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 231214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->PrelinkImage(); 231329bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov si->LinkImage(nullptr); 2314c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif 2315c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov} 2316c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 2317c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/* 2318d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below. 2319d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 23200d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__) 23210d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64" 23220d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else 23230d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker" 23240d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif 232507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanovstatic soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0, 0); 2326d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2327d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list. 2328d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text" 2329d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to 2330d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol. 2331d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't 2332d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list. 2333d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 2334d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) { 2335d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov linker_soinfo_for_gdb.base = linker_base; 2336d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2337d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov /* 2338d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Set the dynamic field in the link map otherwise gdb will complain with 2339d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * the following: 2340d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * warning: .dynamic section for "/system/bin/linker" is not at the 2341d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * expected address (wrong library or version mismatch?) 2342d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 2343d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base); 2344d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff); 2345d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, 2346e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian &linker_soinfo_for_gdb.dynamic, nullptr); 2347d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); 2348d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2349d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2350d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* 2351468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and 2352468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs 2353468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point. 2354468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 23550266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { 23561a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING 23576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov struct timeval t0, t1; 23586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t0, 0); 23591a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif 23601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Initialize environment functions, and get to the ELF aux vectors table. 23626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_env_init(args); 2363be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 23646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // If this is a setuid/setgid program, close the security hole described in 23656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc 23666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (get_AT_SECURE()) { 23676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov nullify_closed_stdio(); 23686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 23698d3e91d4f842911366155845afb3cfbdad0b4cadNick Kralevich 23706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov debuggerd_init(); 23711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Get a few environment variables. 23736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* LD_DEBUG = linker_env_get("LD_DEBUG"); 23746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (LD_DEBUG != nullptr) { 23756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_ld_debug_verbosity = atoi(LD_DEBUG); 23766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2377be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 23786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Normally, these are cleaned by linker_env_init, but the test 23796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // doesn't cost us anything. 23806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpath_env = nullptr; 23816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpreload_env = nullptr; 23826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!get_AT_SECURE()) { 23836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ldpath_env = linker_env_get("LD_LIBRARY_PATH"); 23846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ldpreload_env = linker_env_get("LD_PRELOAD"); 23856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 23861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov INFO("[ android linker & debugger ]"); 23881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 238907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL); 23906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 23916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 23926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 23931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* bootstrap the link map, the main exe always needs to be first */ 23956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->flags |= FLAG_EXE; 23966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(si->link_map_head); 23971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = 0; 23996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_name = args.argv[0]; 24006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = nullptr; 24016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = nullptr; 24021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_map = map; 24046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map; 24051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_linker_info_for_gdb(linker_base); 24071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract information passed from the kernel. 24096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR)); 24106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phnum = args.getauxval(AT_PHNUM); 24116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->entry = args.getauxval(AT_ENTRY); 24121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Compute the value of si->base. We can't rely on the fact that 24146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * the first entry is the PHDR because this will not be true 24156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * for certain executables (e.g. some in the NDK unit test suite) 24166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 24176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = 0; 24186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->size = phdr_table_get_load_size(si->phdr, si->phnum); 24196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = 0; 24206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t i = 0; i < si->phnum; ++i) { 24216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->phdr[i].p_type == PT_PHDR) { 24226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr; 24236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset; 24246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 24258180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner } 24266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 24276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->dynamic = nullptr; 24286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->ref_count = 1; 24291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); 24316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (elf_hdr->e_type != ET_DYN) { 24326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n"); 24336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 24346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 24352aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich 24366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). 24376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_LIBRARY_PATH(ldpath_env); 24386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_PRELOAD(ldpreload_env); 24394fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 24406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov somain = si; 24415ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel 24426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->PrelinkImage(); 244314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 24446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Load ld_preloads and dependencies. 24456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov StringLinkedList needed_library_name_list; 24466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t needed_libraries_count = 0; 24476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t ld_preloads_count = 0; 24486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov while (g_ld_preload_names[ld_preloads_count] != nullptr) { 24496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]); 24506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 24516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 245214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 24536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for_each_dt_needed(si, [&](const char* name) { 24546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.push_back(name); 24556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 24566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov }); 245714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 24586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* needed_library_names[needed_libraries_count]; 24596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo* needed_library_si[needed_libraries_count]; 246014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 24616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov memset(needed_library_names, 0, sizeof(needed_library_names)); 24626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); 246314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2464e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) { 24656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); 24666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 24676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 246814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 24696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t i = 0; i<needed_libraries_count; ++i) { 24706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->add_child(needed_library_si[i]); 24716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 247214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 24736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!si->LinkImage(nullptr)) { 24746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 24756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 24766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 24771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov add_vdso(args); 2479c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 24806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->CallPreInitConstructors(); 24819181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 24826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* After the PrelinkImage, the si->load_bias is initialized. 24836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * For so lib, the map->l_addr will be updated in notify_gdb_of_load. 24846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * We need to update this value for so exe here. So Unwind_Backtrace 24856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * for some arch like x86 could work correctly within so exe. 24866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 24876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = si->load_bias; 24886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->CallConstructors(); 2489e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 24901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING 24916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t1, nullptr); 24926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( 24936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - 24946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); 24951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 24961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 24976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0], 24986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocAbsolute], 24996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocRelative], 25006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocCopy], 25016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocSymbol]); 25021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 25031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 25046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 25056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned n; 25066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned i; 25076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned count = 0; 25086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (n = 0; n < 4096; n++) { 25096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (bitmask[n]) { 25106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned x = bitmask[n]; 2511e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__) 25126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 32; i++) { 2513e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else 25146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 8; i++) { 2515e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif 25166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (x & 1) { 25176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count++; 25186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 25196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov x >>= 1; 25201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 25216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 25221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 25236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4); 25246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 25251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 25261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 25271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES 25286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fflush(stdout); 25291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 25301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 25316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Ready to execute '%s' @ %p ]", si->name, reinterpret_cast<void*>(si->entry)); 25326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return si->entry; 25331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2534468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 2535bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only 2536bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library 2537bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself. 2538bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * 2539bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input: 2540bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * elf -> address of ELF header, assumed to be at the start of the file. 2541bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return: 2542bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * load bias, i.e. add the value of any p_vaddr in the file to get 2543bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * the corresponding address in memory. 2544bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */ 25450266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) { 25460266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) offset = elf->e_phoff; 2547faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes const ElfW(Phdr)* phdr_table = reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset); 25480266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum; 2549fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 25500266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) { 2551fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (phdr->p_type == PT_LOAD) { 25520266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr; 2553bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner } 2554fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 2555fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return 0; 2556bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner} 2557bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner 2558efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start(); 2559efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 2560468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 2561468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This 2562468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and 2563468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation(). 2564468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * 2565468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own 2566468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern 2567468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault. 2568468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 25690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) { 257042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes KernelArgumentBlock args(raw_args); 257142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 25720266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) linker_addr = args.getauxval(AT_BASE); 2573efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); 25740266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); 2575faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); 257642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 257707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov soinfo linker_so("[dynamic linker]", nullptr, 0, 0); 257842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 2579efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // If the linker is not acting as PT_INTERP entry_point is equal to 2580efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // _start. Which means that the linker is running as an executable and 2581efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // already linked by PT_INTERP. 2582efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // 2583efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // This happens when user tries to run 'adb shell /system/bin/linker' 2584efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // see also https://code.google.com/p/android/issues/detail?id=63174 2585efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) { 2586efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]); 2587efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov } 2588efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 258942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.base = linker_addr; 259042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); 259142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); 2592851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov linker_so.dynamic = nullptr; 259342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phdr = phdr; 259442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phnum = elf_hdr->e_phnum; 259542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.flags |= FLAG_LINKER; 259642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 259714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { 259842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // It would be nice to print an error message, but if the linker 259942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // can't link itself, there's no guarantee that we'll be able to 2600b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // call write() (because it involves a GOT reference). We may as 2601b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // well try though... 2602b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes const char* msg = "CANNOT LINK EXECUTABLE: "; 2603b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, msg, strlen(msg)); 2604b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf)); 2605b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, "\n", 1); 2606b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes _exit(EXIT_FAILURE); 260742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes } 2608468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 260914241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov __libc_init_tls(args); 261014241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov 2611efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // Initialize the linker's own global variables 26124151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov linker_so.CallConstructors(); 26134151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov 26140d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // Initialize static variables. Note that in order to 26150d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // get correct libdl_info we need to call constructors 26160d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // before get_libdl_info(). 26170d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov solist = get_libdl_info(); 26180d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov sonext = get_libdl_info(); 26190d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 262042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // We have successfully fixed our own relocations. It's safe to run 262142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // the main part of the linker now. 26221728b2396591853345507a063ed6075dfd251706Elliott Hughes args.abort_message_ptr = &g_abort_message; 26230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr); 26245419b9474753d25dff947c7740532f86d130c0beElliott Hughes 2625d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ); 2626d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 262742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // Return the address that the calling assembly stub should jump to. 262842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes return start_address; 2629468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich} 2630