linker.cpp revision f240aa8089ea1574a7d799720efb66528f6ceb99
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 285e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat, 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 291e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, 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; 4200266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes const char* strtab = si->strtab; 4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", 4230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket); 4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) { 4260266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Sym)* s = symtab + n; 4270266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if (strcmp(strtab + s->st_name, name)) continue; 4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // only concern ourselves with global and weak symbol definitions 4300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes switch (ELF_ST_BIND(s->st_info)) { 4310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes case STB_GLOBAL: 4320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes case STB_WEAK: 4330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if (s->st_shndx == SHN_UNDEF) { 434d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov continue; 435d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov } 4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 437d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", 4380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes name, si->name, reinterpret_cast<void*>(s->st_value), 4390266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes static_cast<size_t>(s->st_size)); 440d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov return s; 441d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov case STB_LOCAL: 44202aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov continue; 443d97e9f546ea195686a78e539315b273393609b9eDmitriy Ivanov default: 44412bf3bcdeeaa0dcdc7a4f4e4d11bc2fc3bf6bd7aDmitriy Ivanov __libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'", 44512bf3bcdeeaa0dcdc7a4f4e4d11bc2fc3bf6bd7aDmitriy Ivanov ELF_ST_BIND(s->st_info), name, si->name); 4461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4470266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 4481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 449aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd", 450aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket); 451aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 452aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 453851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 4541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 456e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovsoinfo::soinfo(const char* name, const struct stat* file_stat, int rtld_flags) { 4570d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov memset(this, 0, sizeof(*this)); 4580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 4590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov strlcpy(this->name, name, sizeof(this->name)); 4600d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov flags = FLAG_NEW_SOINFO; 4610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov version = SOINFO_VERSION; 4620d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 463851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (file_stat != nullptr) { 4640d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov set_st_dev(file_stat->st_dev); 4650d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov set_st_ino(file_stat->st_ino); 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 4886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (somain != nullptr) { 4898f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov DEBUG("%s: looking up %s in executable %s", 4908f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov si->name, name, somain->name); 4915ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel 4928f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov // 1. Look for it in the main executable 4938f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov s = soinfo_elf_lookup(somain, elf_hash, name); 4948f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s != nullptr) { 4958f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov *lsi = somain; 4968f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 497c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 4988f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov // 2. Look for it in the ld_preloads 4998f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s == nullptr) { 5006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (int i = 0; g_ld_preloads[i] != NULL; i++) { 5016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name); 5026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s != nullptr) { 5038f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov *lsi = g_ld_preloads[i]; 5048f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov break; 5056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5078f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 508c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 5098f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov /* Look for symbols in the local scope (the object who is 5108f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * searching). This happens with C++ templates on x86 for some 5118f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * reason. 5128f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * 5138f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * Notes on weak symbols: 5148f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * The ELF specs are ambiguous about treatment of weak definitions in 5158f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * dynamic linking. Some systems return the first definition found 5168f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * and some the first non-weak definition. This is system dependent. 5178f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov * Here we return the first definition found for simplicity. */ 5186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 5198f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s == nullptr) { 5206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = soinfo_elf_lookup(si, elf_hash, name); 5216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s != nullptr) { 5226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *lsi = si; 5236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 5278f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s == nullptr) { 5288f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov si->get_children().visit([&](soinfo* child) { 5298f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov DEBUG("%s: looking up %s in %s", si->name, name, child->name); 5308f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov s = soinfo_elf_lookup(child, elf_hash, name); 5318f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s != nullptr) { 5328f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov *lsi = child; 5338f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov return false; 5348f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 5358f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov return true; 5368f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov }); 5378f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 5386ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 5396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s != nullptr) { 5406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " 5416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov "found in %s, base = %p, load bias = %p", 5426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->name, name, reinterpret_cast<void*>(s->st_value), 5436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*lsi)->name, reinterpret_cast<void*>((*lsi)->base), 5446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reinterpret_cast<void*>((*lsi)->load_bias)); 5456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 5478f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov return s; 5486ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev} 5496ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 5500cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator. 5510cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 5520cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator { 5530cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 5540cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void* alloc() { 5550cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return allocator_.alloc(); 5560cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 5570cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5580cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(void* ptr) { 5590cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov allocator_.free(ptr); 5600cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 5614bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov 5620cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private: 5630cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static LinkerBlockAllocator allocator_; 5640cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 5650cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5660cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 5670cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size); 5680cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5690cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T> 5700cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator { 5710cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 5720cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static T* alloc() { 5730cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc()); 5740cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 5750cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 5760cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(T* ptr) { 5770cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SizeBasedAllocator<sizeof(T)>::free(ptr); 5780cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 5790cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 5800cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 58114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask { 58214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public: 58314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct deleter_t { 58414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov void operator()(LoadTask* t) { 58514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TypeBasedAllocator<LoadTask>::free(t); 58614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 58714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }; 588a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 58914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov typedef UniquePtr<LoadTask, deleter_t> unique_ptr; 590d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom 59114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov static deleter_t deleter; 59214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 59314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov static LoadTask* create(const char* name, soinfo* needed_by) { 59414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc(); 59514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return new (ptr) LoadTask(name, needed_by); 596aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 597a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 59814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* get_name() const { 59914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return name_; 600a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 60114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 60214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* get_needed_by() const { 60314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return needed_by_; 60414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 60514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private: 60614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask(const char* name, soinfo* needed_by) 60714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov : name_(name), needed_by_(needed_by) {} 60814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 60914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name_; 61014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed_by_; 61114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 61214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); 613aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}; 614aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 61514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T> 61614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>; 61714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 61814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList; 61914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList; 62014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<LoadTask> LoadTaskList; 62114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 62214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 623aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov// This is used by dlsym(3). It performs symbol lookup only within the 624aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov// specified soinfo object and its dependencies in breadth first order. 62502aa70589d22fa9b65da43de705d6de2715870c6Dmitriy IvanovElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { 6260cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visit_list; 6270cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visited; 6280cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 629aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov visit_list.push_back(si); 630aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov soinfo* current_soinfo; 631aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov while ((current_soinfo = visit_list.pop_front()) != nullptr) { 632042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov if (visited.contains(current_soinfo)) { 633042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov continue; 634042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov } 635042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov 63602aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name); 637aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 638aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov if (result != nullptr) { 639aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov *found = current_soinfo; 640aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov return result; 641aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 642042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov visited.push_back(current_soinfo); 643aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 644aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov current_soinfo->get_children().for_each([&](soinfo* child) { 645aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov visit_list.push_back(child); 646aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov }); 647aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 648aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 649aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov return nullptr; 6501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 652d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the 653d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom start value is null (for RTLD_DEFAULT), the search starts at the 654d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom beginning of the global solist. Otherwise the search starts at the 655d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom specified soinfo (for RTLD_NEXT). 6566ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */ 65702aa70589d22fa9b65da43de705d6de2715870c6Dmitriy IvanovElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) { 658cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes unsigned elf_hash = elfhash(name); 6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 660851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (start == nullptr) { 661cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes start = solist; 662cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 6631698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer 664851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov ElfW(Sym)* s = nullptr; 665851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) { 666e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) { 667e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov continue; 668e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 669e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 67002aa70589d22fa9b65da43de705d6de2715870c6Dmitriy Ivanov s = soinfo_elf_lookup(si, elf_hash, name); 671851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 672cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes *found = si; 673cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes break; 6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 675cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 677851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 678c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p", 679c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base)); 680cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 682cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes return s; 6831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 685fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) { 6860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p); 687851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 688fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (address >= si->base && address - si->base < si->size) { 689fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return si; 690e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 691fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 692851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 693e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 694e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 6950266ae5f884d72da58f33a072e865ba131234a5eElliott HughesElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) { 6960266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - si->base; 697fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 698fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // Search the library's symbol table for any defined symbol which 699fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // contains this address. 700fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng for (size_t i = 0; i < si->nchain; ++i) { 7010266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Sym)* sym = &si->symtab[i]; 702fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (sym->st_shndx != SHN_UNDEF && 703fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng soaddr >= sym->st_value && 704fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng soaddr < sym->st_value + sym->st_size) { 705fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return sym; 706e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 707fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 708e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 709851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 710e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 711e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 712124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library_on_path(const char* name, const char* const paths[]) { 713124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes char buf[512]; 714851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (size_t i = 0; paths[i] != nullptr; ++i) { 7151e980b6bc8315d00a07312b25486531247abd98cElliott Hughes int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name); 716124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (n < 0 || n >= static_cast<int>(sizeof(buf))) { 717ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name); 718124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes continue; 7191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 720124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC)); 721124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (fd != -1) { 722124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return fd; 723124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 724124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 725124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return -1; 7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 728124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughesstatic int open_library(const char* name) { 729ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ opening %s ]", name); 7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 731124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes // If the name contains a slash, we should attempt to open it directly and not search the paths. 732851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (strchr(name, '/') != nullptr) { 7336971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC)); 7346971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes if (fd != -1) { 7356971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes return fd; 7366971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes } 7376971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now. 7385ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#if defined(__LP64__) 739e43c4a7a665032a29cb5ec15d4adbf81ea199220Dmitriy Ivanov return -1; 7405ca7ed9005ea16733d7c87d7154473b7a500be0cDmitriy Ivanov#endif 741124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 743124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths. 7441728b2396591853345507a063ed6075dfd251706Elliott Hughes int fd = open_library_on_path(name, g_ld_library_paths); 745124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (fd == -1) { 7461728b2396591853345507a063ed6075dfd251706Elliott Hughes fd = open_library_on_path(name, kDefaultLdPaths); 747124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 748124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return fd; 7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 75114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F> 75214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) { 75314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { 75414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (d->d_tag == DT_NEEDED) { 75514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov action(si->strtab + d->d_un.d_val); 756d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 75714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 75814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 759d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 760e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { 76114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov int fd = -1; 76214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov ScopedFd file_guard(-1); 763d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 76414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { 76514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov fd = extinfo->library_fd; 76614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } else { 76714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Open the file. 76814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov fd = open_library(name); 76914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (fd == -1) { 77014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DL_ERR("library \"%s\" not found", name); 771498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov return nullptr; 772498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov } 773b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 77414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov file_guard.reset(fd); 77514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 77623363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner 77714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct stat file_stat; 77814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { 77914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); 78014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 78114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 782d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 78314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Check for symlink and other situations where 78414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // file can have different names. 78514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 78614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si->get_st_dev() != 0 && 78714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->get_st_ino() != 0 && 78814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->get_st_dev() == file_stat.st_dev && 78914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->get_st_ino() == file_stat.st_ino) { 79014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TRACE("library \"%s\" is already loaded under different name/path \"%s\" - will return existing soinfo", name, si->name); 79114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 792498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov } 79314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 794d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 795e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if ((rtld_flags & RTLD_NOLOAD) != 0) { 796a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); 79714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 79814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 799a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 80014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Read the ELF header and load the segments. 80114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov ElfReader elf_reader(name, fd); 80214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!elf_reader.Load(extinfo)) { 80314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 80414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 805d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 806e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, rtld_flags); 80714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == nullptr) { 80814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 80914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 81014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->base = elf_reader.load_start(); 81114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->size = elf_reader.load_size(); 81214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->load_bias = elf_reader.load_bias(); 81314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->phnum = elf_reader.phdr_count(); 81414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->phdr = elf_reader.loaded_phdr(); 81514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 81614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!si->PrelinkImage()) { 81714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_free(si); 81814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 81914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 820a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 82114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for_each_dt_needed(si, [&] (const char* name) { 82214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.push_back(LoadTask::create(name, si)); 82314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 82414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 82514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 8261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 8271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 828489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanovstatic soinfo *find_loaded_library_by_name(const char* name) { 829489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov const char* search_name = SEARCH_NAME(name); 830851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 831489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov if (!strcmp(search_name, si->name)) { 832489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov return si; 83312c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel } 834489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov } 835851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 83612c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel} 83712c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel 838e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) { 839d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 840489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov soinfo* si = find_loaded_library_by_name(name); 841b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 842b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // Library might still be loaded, the accurate detection 84314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // of this fact is done by load_library. 844851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (si == nullptr) { 845b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov TRACE("[ '%s' has not been found by name. Trying harder...]", name); 846e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov si = load_library(load_tasks, name, rtld_flags, extinfo); 847b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov } 848b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 84914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return si; 85014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 85114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 85214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si); 85314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 85414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic bool is_recursive(soinfo* si, soinfo* parent) { 85514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (parent == nullptr) { 85614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 85714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 85814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 85914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == parent) { 860b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov DL_ERR("recursive link to \"%s\"", si->name); 86114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return true; 862d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 863a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 86414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return !parent->get_parents().visit([&](soinfo* grandparent) { 86514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return !is_recursive(si, grandparent); 86614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 867a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov} 868a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 86914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[], 870e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) { 87114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 0: prepare. 87214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTaskList load_tasks; 87314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (size_t i = 0; i < library_names_size; ++i) { 87414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name = library_names[i]; 87514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.push_back(LoadTask::create(name, nullptr)); 87614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 87714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 87814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Libraries added to this list in reverse order so that we can 87914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // start linking from bottom-up - see step 2. 88014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov SoinfoLinkedList found_libs; 88114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov size_t soinfos_size = 0; 88214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 883d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov auto failure_guard = make_scope_guard([&]() { 88414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Housekeeping 88514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov load_tasks.for_each([] (LoadTask* t) { 88614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask::deleter(t); 88714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 88814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 88914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (size_t i = 0; i<soinfos_size; ++i) { 89014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_unload(soinfos[i]); 89114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 89214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 89314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 89414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order. 89514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) { 896e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo); 89714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == nullptr) { 89814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 89914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 90014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 90114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed_by = task->get_needed_by(); 90214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 90314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (is_recursive(si, needed_by)) { 90414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 90514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 90614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 907498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov si->ref_count++; 90814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (needed_by != nullptr) { 90914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov needed_by->add_child(si); 91014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 91114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov found_libs.push_front(si); 91214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 91314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // When ld_preloads is not null first 91414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // ld_preloads_size libs are in fact ld_preloads. 91514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (ld_preloads != nullptr && soinfos_size < ld_preloads_size) { 91614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov ld_preloads[soinfos_size] = si; 91714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 91814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 91914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (soinfos_size<library_names_size) { 92014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfos[soinfos_size++] = si; 92114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 92214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 92314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 92414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 2: link libraries. 92514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* si; 92614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov while ((si = found_libs.pop_front()) != nullptr) { 92714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if ((si->flags & FLAG_LINKED) == 0) { 92814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!si->LinkImage(extinfo)) { 92914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 93014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 93114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->flags |= FLAG_LINKED; 93214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 933a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 93414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 93514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // All is well - found_libs and load_tasks are empty at this point 93614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // and all libs are successfully linked. 93714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov failure_guard.disable(); 93814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return true; 93914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 94014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 941e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) { 94214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (name == nullptr) { 94314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov somain->ref_count++; 94414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return somain; 94514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 94614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 94714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* si; 94814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 949e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) { 95014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 95114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 95214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 953d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return si; 954d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 955d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 956b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovstatic void soinfo_unload(soinfo* si) { 957ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes if (si->ref_count == 1) { 958ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("unloading '%s'", si->name); 959d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes si->CallDestructors(); 960d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 9610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (si->has_min_version(0)) { 96214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* child = nullptr; 96314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov while ((child = si->get_children().pop_front()) != nullptr) { 96414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TRACE("%s needs to unload %s", si->name, child->name); 96514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_unload(child); 9664bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov } 967d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } else { 96814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov for_each_dt_needed(si, [&] (const char* library_name) { 96914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name); 97014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); 97114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (needed != nullptr) { 97214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo_unload(needed); 97314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } else { 97414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Not found: for example if symlink was deleted between dlopen and dlclose 97514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Since we cannot really handle errors at this point - print and continue. 97614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov PRINT("warning: couldn't find %s needed by %s on unload.", library_name, si->name); 977d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 97814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 9791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 9801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 981d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes notify_gdb_of_unload(si); 982ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes si->ref_count = 0; 983d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov soinfo_free(si); 984d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } else { 985ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes si->ref_count--; 986c620059479c47a78d57086d73726c9adc2f337adElliott Hughes TRACE("not unloading '%s', decrementing ref_count to %zd", si->name, si->ref_count); 987d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 9881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 990a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) { 991052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Use basic string manipulation calls to avoid snprintf. 992052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf indirectly calls pthread_getspecific to get the size of a buffer. 993052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // When debug malloc is enabled, this call returns 0. This in turn causes 994052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf to do nothing, which causes libraries to fail to load. 995052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // See b/17302493 for further details. 996052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Once the above bug is fixed, this code can be modified to use 997052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf again. 998052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2; 999052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris if (buffer_size < required_len) { 1000052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: buffer len %zu, required len %zu", 1001052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris buffer_size, required_len); 1002052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris } 1003052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris char* end = stpcpy(buffer, kDefaultLdPaths[0]); 1004052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris *end = ':'; 1005052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris strcpy(end + 1, kDefaultLdPaths[1]); 1006a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes} 1007a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 1008cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { 1009cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes if (!get_AT_SECURE()) { 1010cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes parse_LD_LIBRARY_PATH(ld_library_path); 1011cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 1012cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 1013cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 10141a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughessoinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { 1015b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) { 1016e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes DL_ERR("invalid flags to dlopen: %x", flags); 1017851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1018e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes } 1019851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (extinfo != nullptr && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) { 10203a8646fc5d9f1a9304251a1d1c8ff9e523d81b40Dmitriy Ivanov DL_ERR("invalid extended flags to android_dlopen_ext: %" PRIx64, extinfo->flags); 1021851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1022012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles) } 1023d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 1024b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov soinfo* si = find_library(name, flags, extinfo); 1025851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (si != nullptr) { 1026d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes si->CallConstructors(); 1027d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1028d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ); 1029d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return si; 1030d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 10311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1032b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid do_dlclose(soinfo* si) { 1033d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 1034b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov soinfo_unload(si); 1035d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ); 10361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 10389aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { 10399aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov typedef ElfW(Addr) (*ifunc_resolver_t)(void); 10409aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr); 10419aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ElfW(Addr) ifunc_addr = ifunc_resolver(); 10429aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", ifunc_resolver, reinterpret_cast<void*>(ifunc_addr)); 1043c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 10449aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return ifunc_addr; 1045c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith} 1046c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 10474eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 104829bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovint soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { 1049c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes for (size_t idx = 0; idx < count; ++idx, ++rela) { 10500266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes unsigned type = ELFW(R_TYPE)(rela->r_info); 10510266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes unsigned sym = ELFW(R_SYM)(rela->r_info); 105229bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + load_bias); 10530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) sym_addr = 0; 1054851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov const char* sym_name = nullptr; 1055c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 105629bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov DEBUG("Processing '%s' relocation at index %zd", name, idx); 1057c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (type == 0) { // R_*_NONE 1058c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes continue; 1059c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 106014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 106114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov ElfW(Sym)* s = nullptr; 106214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* lsi = nullptr; 106314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1064c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (sym != 0) { 106529bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name); 106629bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov s = soinfo_do_lookup(this, sym_name, &lsi); 1067851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s == nullptr) { 1068c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes // We only allow an undefined symbol if this is a weak reference... 106929bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov s = &symtab[sym]; 1070c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 107129bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); 1072c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes return -1; 1073c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1074c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1075c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes /* IHI0044C AAELF 4.5.1.1: 1076c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1077c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes Libraries are not searched to resolve weak references. 1078c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes It is not an error for a weak reference to remain unsatisfied. 1079c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1080c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes During linking, the value of an undefined weak reference is: 1081c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - Zero if the relocation type is absolute 1082c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of the place if the relocation is pc-relative 1083c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of nominal base address if the relocation 1084c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes type is base-relative. 1085c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes */ 1086c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1087c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 1088e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__) 10896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_JUMP_SLOT: 10906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_GLOB_DAT: 10916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 10926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 10936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 10946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_RELATIVE: 10956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_IRELATIVE: 10966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 10976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * The sym_addr was initialized to be zero above, or the relocation 10986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * code below does not care about value of sym_addr. 10996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * No need to do anything. 11006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 11016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1102e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__) 11036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_JUMP_SLOT: 11046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_GLOB_DAT: 11056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_32: 11066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_64: 11076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_RELATIVE: 11086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_IRELATIVE: 11096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // No need to do anything. 11106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 11116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_PC32: 11126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sym_addr = reloc; 11136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 11144eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 11156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 11166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rela, idx); 11176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1118c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1119c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } else { 1120c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes // We got a definition. 11219aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 1122c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1123c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes count_relocation(kRelocSymbol); 1124c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1125c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 1126c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 1127e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__) 11286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_JUMP_SLOT: 1129e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1130e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO JMP_SLOT %16llx <- %16llx %s\n", 11320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend); 1134e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_GLOB_DAT: 1136e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1137e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO GLOB_DAT %16llx <- %16llx %s\n", 11390266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11400266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + rela->r_addend); 1141e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 1143e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1144e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11450266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n", 11460266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11470266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend); 1148e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 1150e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1151e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11520266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n", 11530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) && 11550266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) { 11566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend); 1157e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 11586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 11596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)), 11606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT32_MIN), 11616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT32_MAX)); 11626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1163e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1164e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 1166e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 1167e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n", 11690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), sym_name); 11700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend))) && 11710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) { 11726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend); 1173e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 11746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 11756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + rela->r_addend)), 11766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT16_MIN), 11776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT16_MAX)); 11786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1179e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1180e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL64: 1182e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1183e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n", 11850266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); 11860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + rela->r_addend) - rela->r_offset; 1187e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 11886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL32: 1189e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1190e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 11910266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n", 11920266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); 11930266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT32_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && 11940266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT32_MAX))) { 11956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); 1196e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 11976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 11986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), 11996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT32_MIN), 12006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT32_MAX)); 12016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1202e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1203e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 12046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL16: 1205e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1206e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 12070266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n", 12080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset, sym_name); 12090266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes if ((static_cast<ElfW(Addr)>(INT16_MIN) <= (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && 12100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ((*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= static_cast<ElfW(Addr)>(UINT16_MAX))) { 12116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); 1212e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } else { 12136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 12146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), 12156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(INT16_MIN), 12166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<ElfW(Addr)>(UINT16_MAX)); 12176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1218e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 1219e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1220e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 12216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_RELATIVE: 1222e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 1223e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland MARK(rela->r_offset); 1224e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland if (sym) { 12256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("odd RELATIVE form..."); 12266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1227e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 12280266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n", 122929bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov reloc, (base + rela->r_addend)); 123029bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (base + rela->r_addend); 1231e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1232e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 12336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_IRELATIVE: 12346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 12356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 12366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); 12376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + rela->r_addend); 12386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 12399aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 12406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_COPY: 124176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich /* 124276e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * ET_EXEC is not supported so this should not happen. 124376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 124476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 124576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 124676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * Section 4.7.1.10 "Dynamic relocations" 124776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * R_AARCH64_COPY may only appear in executable objects where e_type is 124876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * set to ET_EXEC. 124976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich */ 125029bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov DL_ERR("%s R_AARCH64_COPY relocations are not supported", name); 125176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich return -1; 12526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_TPREL64: 12530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", 12540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset); 1255e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 12566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_DTPREL32: 12570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n", 12580266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes reloc, (sym_addr + rela->r_addend), rela->r_offset); 1259e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 1260e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__) 12616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_JUMP_SLOT: 12626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 12636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 12646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast<size_t>(reloc), 12656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr + rela->r_addend), sym_name); 12666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 12676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 12686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_GLOB_DAT: 12696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 12706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 12716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %08zx <- %08zx %s", static_cast<size_t>(reloc), 12726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr + rela->r_addend), sym_name); 12736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 12746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 12756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_RELATIVE: 12766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 12776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 12786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (sym) { 12796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("odd RELATIVE form..."); 12806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 12816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 12826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast<size_t>(reloc), 12836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(base)); 12846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = base + rela->r_addend; 12856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 12866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_IRELATIVE: 12876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 12886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 12896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %16llx <- %16llx\n", reloc, (base + rela->r_addend)); 12906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + rela->r_addend); 12916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 12926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_32: 12936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 12946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 12956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 12966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 12976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 12986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 12996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_64: 13006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 13016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 13036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 13046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; 13056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_PC32: 13076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 13086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rela->r_offset); 13096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", 13106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc), 13116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name); 13126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend - reloc; 13136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13144eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 1315e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 13166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 13176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rela, idx); 13186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1319c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1320c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 1321c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes return 0; 1322c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes} 13239918665a45095ad135576f005c0e5307feb366a1Chris Dearman 13249918665a45095ad135576f005c0e5307feb366a1Chris Dearman#else // REL, not RELA. 132529bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovint soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { 13266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t idx = 0; idx < count; ++idx, ++rel) { 13276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned type = ELFW(R_TYPE)(rel->r_info); 13286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. 13296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned sym = ELFW(R_SYM)(rel->r_info); 13306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias); 13316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Addr) sym_addr = 0; 13326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* sym_name = nullptr; 13336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("Processing '%s' relocation at index %zd", name, idx); 13356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (type == 0) { // R_*_NONE 13366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 13376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 13386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* s = nullptr; 13406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo* lsi = nullptr; 13416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (sym != 0) { 13436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name); 13446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = soinfo_do_lookup(this, sym_name, &lsi); 13456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s == nullptr) { 13466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We only allow an undefined symbol if this is a weak reference... 13476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = &symtab[sym]; 13486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 13496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); 13506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 1351d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 135214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 13536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* IHI0044C AAELF 4.5.1.1: 13546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov Libraries are not searched to resolve weak references. 13566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov It is not an error for a weak reference to remain 13576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsatisfied. 13586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov During linking, the value of an undefined weak reference is: 13606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov - Zero if the relocation type is absolute 13616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov - The address of the place if the relocation is pc-relative 13626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov - The address of nominal base address if the relocation 13636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov type is base-relative. 13646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 13656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 13666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (type) { 13674eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 13686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_JUMP_SLOT: 13696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_GLOB_DAT: 13706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_ABS32: 13716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_RELATIVE: /* Don't care. */ 13726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // sym_addr was initialized to be zero above or relocation 13736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // code below does not care about value of sym_addr. 13746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // No need to do anything. 13756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13764eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 13776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_JMP_SLOT: 13786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_GLOB_DAT: 13796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_32: 13806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_RELATIVE: /* Don't care. */ 13816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_IRELATIVE: 13826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // sym_addr was initialized to be zero above or relocation 13836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // code below does not care about value of sym_addr. 13846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // No need to do anything. 13856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_PC32: 13876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sym_addr = reloc; 13886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 13894eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 1390e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan 13914eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 13926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_COPY: 13936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Fall through. Can't really copy if weak symbol is not found at run-time. 13944eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 13956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 13966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx); 13976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 13981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 13996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 14006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We got a definition. 14016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 14026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 14036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocSymbol); 14046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 14051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 14066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (type) { 14074eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 14086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_JUMP_SLOT: 14096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); 14126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 14136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_GLOB_DAT: 14156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); 14186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 14196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_ABS32: 14216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name); 14246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 14256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_REL32: 14276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 14286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s", 14306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, sym_addr, rel->r_offset, sym_name); 14316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset; 14326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_COPY: 14346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 14356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * ET_EXEC is not supported so this should not happen. 14366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 14376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 14386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 14396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * Section 4.7.1.10 "Dynamic relocations" 14406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * R_ARM_COPY may only appear in executable objects where e_type is 14416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * set to ET_EXEC. 14426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 14436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("%s R_ARM_COPY relocations are not supported", name); 14446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 14454eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 14466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_JMP_SLOT: 14476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); 14506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 14516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_GLOB_DAT: 14536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name); 14566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; 14576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_32: 14596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 14606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); 14626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 14636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_PC32: 14656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 14666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", 14686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); 14696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc); 14706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14714eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__mips__) 14726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_MIPS_REL32: 14739918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if defined(__LP64__) 14746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // MIPS Elf64_Rel entries contain compound relocations 14756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case 14766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 || 14776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) { 14786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)", 14796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov type, (unsigned)ELF64_R_TYPE2(rel->r_info), 14806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx); 14816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 14826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 14839918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif 14846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 14856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 14866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc), 14876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*"); 14886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s) { 14896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 14906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 14916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += base; 14926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 14936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 14944eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 14954eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes 14964eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 14976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_RELATIVE: 14984eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 14996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_RELATIVE: 15004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 15016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 15026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (sym) { 15046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("odd RELATIVE form..."); 15056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 15066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p", 15086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base)); 15096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += base; 15106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15119aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#if defined(__i386__) 15126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_IRELATIVE: 15136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 15146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 15156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %p <- %p", reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base)); 15166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + *reinterpret_cast<ElfW(Addr)*>(reloc)); 15176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 15189aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif 15191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 15206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 15216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); 15226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 15231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 15246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return 0; 15261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1527c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 15281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 15294eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 153029bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanovstatic bool mips_relocate_got(soinfo* si) { 15316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Addr)** got = si->plt_got; 15326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (got == nullptr) { 15336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 15346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned local_gotno = si->mips_local_gotno; 15366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned gotsym = si->mips_gotsym; 15376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned symtabno = si->mips_symtabno; 15386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* symtab = si->symtab; 15396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 15406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // got[0] is the address of the lazy resolver function. 15416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // got[1] may be used for a GNU extension. 15426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set it to a recognizable address in case someone calls it (should be _rtld_bind_start). 15436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // FIXME: maybe this should be in a separate routine? 15446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((si->flags & FLAG_LINKER) == 0) { 15456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t g = 0; 15466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadbeef); 15476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (reinterpret_cast<intptr_t>(got[g]) < 0) { 15486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadfeed); 154987c358524e479235aa6241736d2ce325f89daafcBrian Carlstrom } 15506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Relocate the local GOT entries. 15516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (; g < local_gotno; g++) { 15526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got[g] = reinterpret_cast<ElfW(Addr)*>(reinterpret_cast<uintptr_t>(got[g]) + si->load_bias); 1553d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 15546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 1555d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 15566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Now for the global GOT entries... 15576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* sym = symtab + gotsym; 15586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov got = si->plt_got + local_gotno; 15596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { 15606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // This is an undefined reference... try to locate it. 15616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* sym_name = si->strtab + sym->st_name; 15626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo* lsi = nullptr; 15636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); 15646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s == nullptr) { 15656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // We only allow an undefined symbol if this is a weak reference. 15666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov s = &symtab[g]; 15676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 15686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("cannot locate \"%s\"...", sym_name); 15696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 15706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *got = 0; 15726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 15736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // FIXME: is this sufficient? 15746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // For reference see NetBSD link loader 15756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy 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 15766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *got = reinterpret_cast<ElfW(Addr)*>(lsi->resolve_symbol_address(s)); 1577d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 15786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 15796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 1580d7daacb46372132ae3f0121647074936c304b572Raghu Gandham} 1581d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif 1582d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 1583812fd4263a005b88f3b4222baa910114f938d594Kito Chengvoid soinfo::CallArray(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) { 1584851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (functions == nullptr) { 1585d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 1586d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 15878215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1588c620059479c47a78d57086d73726c9adc2f337adElliott Hughes TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, name); 15898215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1590ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int begin = reverse ? (count - 1) : 0; 1591ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int end = reverse ? -1 : count; 1592ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int step = reverse ? -1 : 1; 15938215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1594ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes for (int i = begin; i != end; i += step) { 1595ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]); 1596ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes CallFunction("function", functions[i]); 1597d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1598d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1599ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ Done calling %s for '%s' ]", array_name, name); 16001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1602812fd4263a005b88f3b4222baa910114f938d594Kito Chengvoid soinfo::CallFunction(const char* function_name __unused, linker_function_t function) { 1603851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) { 1604d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 1605d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1606d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1607ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, name); 1608d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes function(); 1609ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, name); 1610db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes 1611db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes // The function may have called dlopen(3) or dlclose(3), so we need to ensure our data structures 1612db492b3ca753c4ef688d0daf648294de0c89145eElliott Hughes // are still writable. This happens with our debug malloc (see http://b/7941716). 1613d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 16149181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov} 16159181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 1616d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallPreInitConstructors() { 16178147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_PREINIT_ARRAY functions are called before any other constructors for executables, 16188147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // but ignored in a shared library. 1619d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallArray("DT_PREINIT_ARRAY", preinit_array, preinit_array_count, false); 1620d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 1621e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 1622d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallConstructors() { 1623d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes if (constructors_called) { 1624d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 1625d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 1626e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 1627d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // We set constructors_called before actually calling the constructors, otherwise it doesn't 1628d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // protect against recursive constructor calls. One simple example of constructor recursion 1629d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so: 1630d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 1. The program depends on libc, so libc's constructor is called here. 1631d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so. 1632d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 3. dlopen() calls the constructors on the newly created 1633d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // soinfo for libc_malloc_debug_leak.so. 1634d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 4. The debug .so depends on libc, so CallConstructors is 1635d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // called again with the libc soinfo. If it doesn't trigger the early- 1636d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // out above, the libc constructor will be called again (recursively!). 1637d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes constructors_called = true; 1638d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 1639851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) { 16408147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // The GNU dynamic linker silently ignores these, but we warn the developer. 1641c620059479c47a78d57086d73726c9adc2f337adElliott Hughes PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!", 16428147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes name, preinit_array_count); 1643d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1645d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov get_children().for_each([] (soinfo* si) { 1646d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov si->CallConstructors(); 1647d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 16481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 16498147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes TRACE("\"%s\": calling constructors", name); 16508147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 16518147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_INIT should be called before DT_INIT_ARRAY if both are present. 1652d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallFunction("DT_INIT", init_func); 1653d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallArray("DT_INIT_ARRAY", init_array, init_array_count, false); 1654e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov} 16558215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 1656d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughesvoid soinfo::CallDestructors() { 165714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!constructors_called) { 165814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return; 165914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 16608147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes TRACE("\"%s\": calling destructors", name); 16618147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 16628147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI_ARRAY must be parsed in reverse order. 1663d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallArray("DT_FINI_ARRAY", fini_array, fini_array_count, true); 16648147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 16658147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI should be called after DT_FINI_ARRAY if both are present. 1666d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes CallFunction("DT_FINI", fini_func); 1667b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 1668b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // This is needed on second call to dlopen 1669b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // after library has been unloaded with RTLD_NODELETE 1670b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov constructors_called = false; 16711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1673d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) { 16740d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 1675b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov child->parents.push_back(this); 1676b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov this->children.push_back(child); 1677d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1678d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1679d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1680d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() { 16810d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (!has_min_version(0)) { 1682d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return; 1683d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1684d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1685d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 1. Untie connected soinfos from 'this'. 1686d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov children.for_each([&] (soinfo* child) { 1687d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov child->parents.remove_if([&] (const soinfo* parent) { 1688d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return parent == this; 1689d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1690d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1691d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1692d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov parents.for_each([&] (soinfo* parent) { 16934bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov parent->children.remove_if([&] (const soinfo* child) { 1694d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return child == this; 1695d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1696d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 1697d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1698d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 2. Once everything untied - clear local lists. 1699d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov parents.clear(); 1700d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov children.clear(); 1701d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1702d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1703d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::set_st_dev(dev_t dev) { 17040d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov st_dev = dev; 1706d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1707d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1708d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1709d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::set_st_ino(ino_t ino) { 17100d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17110d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov st_ino = ino; 1712d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1713d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1714d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1715d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovdev_t soinfo::get_st_dev() { 17160d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17170d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return st_dev; 1718d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1719d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 17200d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 1721d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}; 1722d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1723d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovino_t soinfo::get_st_ino() { 17240d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17250d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return st_ino; 1726d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1727d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 17280d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 1729d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1730d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1731e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovint soinfo::get_rtld_flags() { 1732e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (has_min_version(1)) { 1733e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov return rtld_flags; 1734e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 1735e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 1736e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov return 0; 1737e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov} 1738e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 173914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if 1740d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set. 1741d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list; 1742d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1743d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() { 17440d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 17450d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return this->children; 1746d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 1747d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 17480d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return g_empty_list; 1749d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 1750d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 175114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() { 175214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if ((this->flags & FLAG_NEW_SOINFO) == 0) { 175314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return g_empty_list; 175414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 175514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 175614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return this->parents; 175714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 175814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 17599aea164457c269c475592da36b4655d45f55c7bcDmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) { 17609aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { 17619aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return call_ifunc_resolver(s->st_value + load_bias); 17629aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov } 17639aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 17649aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return static_cast<ElfW(Addr)>(s->st_value + load_bias); 17659aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov} 17669aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 17671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with 17681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /dev/null. */ 17695419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic int nullify_closed_stdio() { 17706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int dev_null, i, status; 17716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int return_value = 0; 17721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); 17746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dev_null < 0) { 17756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("cannot open /dev/null: %s", strerror(errno)); 17766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return -1; 17776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 17786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null); 17796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 17806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If any of the stdio file descriptors is valid and not associated 17816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov with /dev/null, dup /dev/null to it. */ 17826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 3; i++) { 17836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If it is /dev/null already, we are done. */ 17846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (i == dev_null) { 17856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 17861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 17871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Nullifying stdio file descriptor %d]", i); 17896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL)); 17901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If file is opened, we are good. */ 17926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (status != -1) { 17936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 17946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 17951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 17966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* The only error we allow is that the file descriptor does not 17976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exist, in which case we dup /dev/null to it. */ 17986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (errno != EBADF) { 17996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("fcntl failed: %s", strerror(errno)); 18006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return_value = -1; 18016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 18026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Try dupping /dev/null to this stdio file descriptor and 18056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov repeat if there is a signal. Note that any errors in closing 18066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov the stdio descriptor are lost. */ 18076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov status = TEMP_FAILURE_RETRY(dup2(dev_null, i)); 18086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (status < 0) { 18096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("dup2 failed: %s", strerror(errno)); 18106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return_value = -1; 18116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov continue; 18121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 18136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* If /dev/null is not one of the stdio file descriptors, close it. */ 18166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dev_null > 2) { 18176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null); 18186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov status = TEMP_FAILURE_RETRY(close(dev_null)); 18196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (status == -1) { 18206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("close failed: %s", strerror(errno)); 18216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return_value = -1; 18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 18236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 18256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return return_value; 18261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 182814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovbool soinfo::PrelinkImage() { 18296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic); 1830498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov 18316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can't log anything until the linker is relocated */ 18326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov bool relocating_linker = (flags & FLAG_LINKER) != 0; 18336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 18346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov INFO("[ linking %s ]", name); 18356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags); 18366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 18386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Extract dynamic section */ 18396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Word) dynamic_flags = phdr->p_flags; 18406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dynamic == nullptr) { 1841b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner if (!relocating_linker) { 18426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("missing PT_DYNAMIC in \"%s\"", name); 1843b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner } 18446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 18456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 18466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 18476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("dynamic = %p", dynamic); 184863f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner } 18496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 185063f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 18514eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 18526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, 18536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov &ARM_exidx, &ARM_exidx_count); 185463f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif 185563f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 18566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract useful information from dynamic section. 18576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov uint32_t needed_count = 0; 18586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 18596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", 18606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 18616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (d->d_tag) { 18624a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SONAME: 18634a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // TODO: glibc dynamic linker uses this name for 18644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // initial library lookup; consider doing the same here. 18654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 18666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_HASH: 18676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 18686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 18696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8); 18706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); 18716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 18726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_STRTAB: 18736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr); 18746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 18756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMTAB: 18766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr); 18776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 18784a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SYMENT: 18794a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Sym))) { 1880f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_SYMENT: %zd", static_cast<size_t>(d->d_un.d_val)); 18814a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 18824a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 18834a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 18844eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if !defined(__LP64__) 18856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTREL: 18866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val != DT_REL) { 18876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unsupported DT_RELA in \"%s\"", name); 18886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 18896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 18906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 1891c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 18926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_JMPREL: 18934eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 18946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 1895c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 18966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 1897c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 18986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 18996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTRELSZ: 19004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 19016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); 1902c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 19036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); 1904c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 19056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTGOT: 19074a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__) 19086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Used by mips and mips64. 19096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov plt_got = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr); 1910c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 19114a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // Ignore for other platforms... (because RTLD_LAZY is not supported) 19124a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 19136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_DEBUG: 19146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_DEBUG entry to the address of _r_debug for GDB 19156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // if the dynamic table is writable 19169918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64 19179918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree. 191814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as 19199918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable. 19209918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__)) 19216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((dynamic_flags & PF_W) != 0) { 19226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug); 19236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 19246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19259918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif 19264eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 19276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 19286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 19296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELASZ: 19316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); 19326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19334a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELAENT: 19344a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rela))) { 1935f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val)); 19364a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 19374a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 19384a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 19394a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELACOUNT: 19404a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // ignored (see DT_RELCOUNT comments for details) 19414a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 19426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 19436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unsupported DT_REL in \"%s\"", name); 19446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 19456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 19466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unsupported DT_RELSZ in \"%s\"", name); 19476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 1948c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 19496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 19506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 19516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 19536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); 19546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19554a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELENT: 19564a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rel))) { 1957f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val)); 19584a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 19594a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 19604a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 19614a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELCOUNT: 19624a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // "Indicates that all RELATIVE relocations have been concatenated together, 19634a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // and specifies the RELATIVE relocation count." 19644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // 19654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // TODO: Spec also mentions that this can be used to optimize relocation process; 19664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // Not currently used by bionic linker - ignored. 19674a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 19686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 19696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unsupported DT_RELA in \"%s\"", name); 19706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 1971c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 19726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT: 19736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 19746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s constructors (DT_INIT) found at %p", name, init_func); 19756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI: 19776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fini_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 19786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func); 19796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAY: 19816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 19826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array); 19836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAYSZ: 19856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); 19866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAY: 19886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fini_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 19896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array); 19906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAYSZ: 19926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); 19936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAY: 19956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov preinit_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 19966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array); 19976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 19986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAYSZ: 19996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); 20006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_TEXTREL: 2002e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__) 20036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name); 20046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2005e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else 20066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov has_text_relocations = true; 20076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2008e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 20096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMBOLIC: 20108f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov // ignored 20116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_NEEDED: 20136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_count; 20146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FLAGS: 20166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val & DF_TEXTREL) { 2017e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if defined(__LP64__) 20186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name); 20196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2020e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#else 20216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov has_text_relocations = true; 2022e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 20236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 20246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20254eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 20266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_STRSZ: 20276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_MAP: 20296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. 20306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 20316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr); 20326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *dp = &_r_debug; 20336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 20346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_VERSION: 20366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_FLAGS: 20376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_BASE_ADDRESS: 20386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_UNREFEXTNO: 20396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2040d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 20416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_SYMTABNO: 20426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov mips_symtabno = d->d_un.d_val; 20436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2044d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 20456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_LOCAL_GOTNO: 20466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov mips_local_gotno = d->d_un.d_val; 20476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 2048d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 20496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_GOTSYM: 20506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov mips_gotsym = d->d_un.d_val; 20516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20524eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 2053d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 20546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 20558f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (!relocating_linker) { 20568f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov DL_WARN("%s: unused DT entry: type %p arg %p", name, 20578f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 20588f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 20596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 20601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 20616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 20621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", 20646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reinterpret_cast<void*>(base), strtab, symtab); 20651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 20666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Sanity checks. 20676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (relocating_linker && needed_count != 0) { 20686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); 20696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 20706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 20716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (nbucket == 0) { 20726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name); 20736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 20746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 20756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (strtab == 0) { 20766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("empty/missing DT_STRTAB in \"%s\"", name); 20776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 20786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 20796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (symtab == 0) { 20806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); 20816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 20826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 20836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 208414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 20851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 208614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovbool soinfo::LinkImage(const android_dlextinfo* extinfo) { 20871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2088e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__) 20896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (has_text_relocations) { 20906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Make segments writable to allow text relocations to work properly. We will later call 20916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // phdr_table_protect_segments() after all of them are applied and all constructors are run. 20926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_WARN("%s has text relocations. This is wasting memory and prevents " 20936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov "security hardening. Please fix.", name); 20946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 20956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 20966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 20976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 20985135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich } 20996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2100e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 21015135b3ae6ebc460418f7917bd36b368340e48d5aNick Kralevich 21024eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 21036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (rela != nullptr) { 21046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s ]", name); 21056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(rela, rela_count)) { 21066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2107c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 21086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (plt_rela != nullptr) { 21106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s plt ]", name); 21116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(plt_rela, plt_rela_count)) { 21126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 21146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21159aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else 21166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (rel != nullptr) { 21176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s ]", name); 21186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(rel, rel_count)) { 21196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 21216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (plt_rel != nullptr) { 21236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ relocating %s plt ]", name); 21246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (Relocate(plt_rel, plt_rel_count)) { 21256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2126c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith } 21276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21289aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif 2129c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 21304eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 21316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!mips_relocate_got(this)) { 21326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2134d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif 2135d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 21366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("[ finished linking %s ]", name); 21371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2138e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#if !defined(__LP64__) 21396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (has_text_relocations) { 21406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // All relocations are done, we can protect our segments back to read-only. 21416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 21426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't protect segments for \"%s\": %s", 21436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 21446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 21466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2147e4d792adb8d6f9228b9ac9dc1ad7f43b271f085fElliott Hughes#endif 21481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 21496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can also turn on GNU RELRO protection */ 21506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { 21516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", 21526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 21536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21559ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich 21566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Handle serializing/sharing the RELRO segment */ 21576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { 21586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, 21596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 21606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", 21616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 21626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 2163183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) } 21646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { 21656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, 21666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 21676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", 21686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov name, strerror(errno)); 21696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 21706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 21716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2172183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) 21736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov notify_gdb_of_load(this); 21746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 21751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 21761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2177468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 2178c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list. 2179c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers. 2180c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc. 2181c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */ 2182812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) { 21834eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR) 21840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR)); 2185851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (ehdr_vdso == nullptr) { 21860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return; 21870266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 2188c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 2189e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* si = soinfo_alloc("[vdso]", nullptr, 0); 2190ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 21910266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff); 21920266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phnum = ehdr_vdso->e_phnum; 21930266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso); 21940266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->size = phdr_table_get_load_size(si->phdr, si->phnum); 21950266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->load_bias = get_elf_exec_load_bias(ehdr_vdso); 2196ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 219714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov si->PrelinkImage(); 219829bbc9dd4c606de9187e46d8899a2a744715c967Dmitriy Ivanov si->LinkImage(nullptr); 2199c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif 2200c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov} 2201c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 2202c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/* 2203d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below. 2204d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 22050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__) 22060d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64" 22070d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else 22080d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker" 22090d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif 2210e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0); 2211d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2212d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list. 2213d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text" 2214d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to 2215d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol. 2216d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't 2217d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list. 2218d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 2219d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) { 2220d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov linker_soinfo_for_gdb.base = linker_base; 2221d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2222d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov /* 2223d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Set the dynamic field in the link map otherwise gdb will complain with 2224d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * the following: 2225d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * warning: .dynamic section for "/system/bin/linker" is not at the 2226d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * expected address (wrong library or version mismatch?) 2227d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 2228d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base); 2229d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff); 2230d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, 223114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov &linker_soinfo_for_gdb.dynamic); 2232d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); 2233d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 2234d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 2235d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* 2236468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and 2237468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs 2238468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point. 2239468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 22400266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { 22411a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING 22426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov struct timeval t0, t1; 22436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t0, 0); 22441a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif 22451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Initialize environment functions, and get to the ELF aux vectors table. 22476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_env_init(args); 2248be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 22496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // If this is a setuid/setgid program, close the security hole described in 22506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc 22516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (get_AT_SECURE()) { 22526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov nullify_closed_stdio(); 22536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22548d3e91d4f842911366155845afb3cfbdad0b4cadNick Kralevich 22556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov debuggerd_init(); 22561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Get a few environment variables. 22586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* LD_DEBUG = linker_env_get("LD_DEBUG"); 22596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (LD_DEBUG != nullptr) { 22606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_ld_debug_verbosity = atoi(LD_DEBUG); 22616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 2262be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 22636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Normally, these are cleaned by linker_env_init, but the test 22646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // doesn't cost us anything. 22656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpath_env = nullptr; 22666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpreload_env = nullptr; 22676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!get_AT_SECURE()) { 22686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ldpath_env = linker_env_get("LD_LIBRARY_PATH"); 22696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ldpreload_env = linker_env_get("LD_PRELOAD"); 22706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov INFO("[ android linker & debugger ]"); 22731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2274e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo* si = soinfo_alloc(args.argv[0], nullptr, RTLD_GLOBAL); 22756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 22766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 22776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 22781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* bootstrap the link map, the main exe always needs to be first */ 22806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->flags |= FLAG_EXE; 22816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(si->link_map_head); 22821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = 0; 22846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_name = args.argv[0]; 22856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_prev = nullptr; 22866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_next = nullptr; 22871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov _r_debug.r_map = map; 22896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug_tail = map; 22901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_linker_info_for_gdb(linker_base); 22921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract information passed from the kernel. 22946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR)); 22956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phnum = args.getauxval(AT_PHNUM); 22966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->entry = args.getauxval(AT_ENTRY); 22971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 22986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Compute the value of si->base. We can't rely on the fact that 22996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * the first entry is the PHDR because this will not be true 23006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * for certain executables (e.g. some in the NDK unit test suite) 23016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 23026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = 0; 23036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->size = phdr_table_get_load_size(si->phdr, si->phnum); 23046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = 0; 23056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t i = 0; i < si->phnum; ++i) { 23066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->phdr[i].p_type == PT_PHDR) { 23076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr; 23086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset; 23096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 23108180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner } 23116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 23126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->dynamic = nullptr; 23136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->ref_count = 1; 23141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); 23166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (elf_hdr->e_type != ET_DYN) { 23176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n"); 23186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 23196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 23202aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich 23216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). 23226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_LIBRARY_PATH(ldpath_env); 23236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_PRELOAD(ldpreload_env); 23244fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 23256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov somain = si; 23265ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel 23276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->PrelinkImage(); 232814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 23296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Load ld_preloads and dependencies. 23306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov StringLinkedList needed_library_name_list; 23316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t needed_libraries_count = 0; 23326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t ld_preloads_count = 0; 23336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov while (g_ld_preload_names[ld_preloads_count] != nullptr) { 23346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.push_back(g_ld_preload_names[ld_preloads_count++]); 23356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 23366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 233714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 23386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for_each_dt_needed(si, [&](const char* name) { 23396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.push_back(name); 23406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 23416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov }); 234214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 23436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* needed_library_names[needed_libraries_count]; 23446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo* needed_library_si[needed_libraries_count]; 234514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 23466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov memset(needed_library_names, 0, sizeof(needed_library_names)); 23476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); 234814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2349e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy 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)) { 23506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer()); 23516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 23526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 235314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 23546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t i = 0; i<needed_libraries_count; ++i) { 23556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->add_child(needed_library_si[i]); 23566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 235714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 23586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!si->LinkImage(nullptr)) { 23596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); 23606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov exit(EXIT_FAILURE); 23616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 23621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov add_vdso(args); 2364c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 23656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->CallPreInitConstructors(); 23669181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 23676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* After the PrelinkImage, the si->load_bias is initialized. 23686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * For so lib, the map->l_addr will be updated in notify_gdb_of_load. 23696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * We need to update this value for so exe here. So Unwind_Backtrace 23706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * for some arch like x86 could work correctly within so exe. 23716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 23726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = si->load_bias; 23736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->CallConstructors(); 2374e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 23751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING 23766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t1, nullptr); 23776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( 23786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - 23796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); 23801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 23811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 23826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0], 23836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocAbsolute], 23846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocRelative], 23856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocCopy], 23866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocSymbol]); 23871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 23881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 23896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 23906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned n; 23916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned i; 23926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned count = 0; 23936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (n = 0; n < 4096; n++) { 23946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (bitmask[n]) { 23956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned x = bitmask[n]; 2396e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__) 23976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 32; i++) { 2398e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else 23996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 8; i++) { 2400e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif 24016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (x & 1) { 24026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count++; 24036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 24046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov x >>= 1; 24051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 24066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 24071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 24086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4); 24096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 24101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 24111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES 24136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fflush(stdout); 24141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 24151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE("[ Ready to execute '%s' @ %p ]", si->name, reinterpret_cast<void*>(si->entry)); 24176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return si->entry; 24181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2419468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 2420bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only 2421bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library 2422bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself. 2423bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * 2424bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input: 2425bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * elf -> address of ELF header, assumed to be at the start of the file. 2426bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return: 2427bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * load bias, i.e. add the value of any p_vaddr in the file to get 2428bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * the corresponding address in memory. 2429bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */ 24300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) { 24310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) offset = elf->e_phoff; 2432faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes const ElfW(Phdr)* phdr_table = reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset); 24330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum; 2434fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 24350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) { 2436fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (phdr->p_type == PT_LOAD) { 24370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr; 2438bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner } 2439fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 2440fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return 0; 2441bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner} 2442bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner 2443efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start(); 2444efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 2445468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 2446468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This 2447468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and 2448468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation(). 2449468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * 2450468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own 2451468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern 2452468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault. 2453468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 24540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) { 245542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes KernelArgumentBlock args(raw_args); 245642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 24570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) linker_addr = args.getauxval(AT_BASE); 2458efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); 24590266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); 2460faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); 246142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 2462e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov soinfo linker_so("[dynamic linker]", nullptr, 0); 246342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 2464efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // If the linker is not acting as PT_INTERP entry_point is equal to 2465efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // _start. Which means that the linker is running as an executable and 2466efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // already linked by PT_INTERP. 2467efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // 2468efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // This happens when user tries to run 'adb shell /system/bin/linker' 2469efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // see also https://code.google.com/p/android/issues/detail?id=63174 2470efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) { 2471efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]); 2472efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov } 2473efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 247442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.base = linker_addr; 247542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); 247642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); 2477851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov linker_so.dynamic = nullptr; 247842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phdr = phdr; 247942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phnum = elf_hdr->e_phnum; 248042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.flags |= FLAG_LINKER; 248142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 248214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr))) { 248342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // It would be nice to print an error message, but if the linker 248442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // can't link itself, there's no guarantee that we'll be able to 2485b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // call write() (because it involves a GOT reference). We may as 2486b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes // well try though... 2487b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes const char* msg = "CANNOT LINK EXECUTABLE: "; 2488b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, msg, strlen(msg)); 2489b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf)); 2490b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes write(2, "\n", 1); 2491b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes _exit(EXIT_FAILURE); 249242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes } 2493468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 249414241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov __libc_init_tls(args); 249514241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov 2496efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // Initialize the linker's own global variables 24974151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov linker_so.CallConstructors(); 24984151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov 24990d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // Initialize static variables. Note that in order to 25000d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // get correct libdl_info we need to call constructors 25010d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // before get_libdl_info(). 25020d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov solist = get_libdl_info(); 25030d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov sonext = get_libdl_info(); 25040d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 250542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // We have successfully fixed our own relocations. It's safe to run 250642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // the main part of the linker now. 25071728b2396591853345507a063ed6075dfd251706Elliott Hughes args.abort_message_ptr = &g_abort_message; 25080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr); 25095419b9474753d25dff947c7740532f86d130c0beElliott Hughes 2510d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov protect_data(PROT_READ); 2511d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 251242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // Return the address that the calling assembly stub should jump to. 251342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes return start_address; 2514468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich} 2515