1114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov/* 2114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * Copyright (C) 2015 The Android Open Source Project 3114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * All rights reserved. 4114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * 5114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * Redistribution and use in source and binary forms, with or without 6114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * modification, are permitted provided that the following conditions 7114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * are met: 8114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * * Redistributions of source code must retain the above copyright 9114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * notice, this list of conditions and the following disclaimer. 10114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * * Redistributions in binary form must reproduce the above copyright 11114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * notice, this list of conditions and the following disclaimer in 12114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * the documentation and/or other materials provided with the 13114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * distribution. 14114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * 15114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov * SUCH DAMAGE. 27114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov */ 28114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 29bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#if !defined(__LP64__) && __mips_isa_rev >= 5 30bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#include <sys/prctl.h> 31bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#endif 32bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 33114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#include "linker.h" 34114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#include "linker_debug.h" 35576a375bc2049d88998b43429a15df0a1011861fDimitry Ivanov#include "linker_globals.h" 36bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#include "linker_phdr.h" 37114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#include "linker_relocs.h" 38fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker_reloc_iterators.h" 3918870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov#include "linker_sleb128.h" 40576a375bc2049d88998b43429a15df0a1011861fDimitry Ivanov#include "linker_soinfo.h" 41fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 427e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanovtemplate bool soinfo::relocate<plain_reloc_iterator>(const VersionTracker& version_tracker, 437e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov plain_reloc_iterator&& rel_iterator, 4418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const soinfo_list_t& global_group, 4518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const soinfo_list_t& local_group); 4618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 4718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovtemplate bool soinfo::relocate<packed_reloc_iterator<sleb128_decoder>>( 487e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov const VersionTracker& version_tracker, 4918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov packed_reloc_iterator<sleb128_decoder>&& rel_iterator, 5018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const soinfo_list_t& global_group, 5118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const soinfo_list_t& local_group); 5218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 53fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanovtemplate <typename ElfRelIteratorT> 547e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanovbool soinfo::relocate(const VersionTracker& version_tracker, 557e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov ElfRelIteratorT&& rel_iterator, 5620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const soinfo_list_t& global_group, 5720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const soinfo_list_t& local_group) { 58fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov for (size_t idx = 0; rel_iterator.has_next(); ++idx) { 59fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov const auto rel = rel_iterator.next(); 60114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 6118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (rel == nullptr) { 6218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 6318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 6418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 65114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov ElfW(Word) type = ELFW(R_TYPE)(rel->r_info); 66114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov ElfW(Word) sym = ELFW(R_SYM)(rel->r_info); 67114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 68114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias); 69114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov ElfW(Addr) sym_addr = 0; 70114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov const char* sym_name = nullptr; 71114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 72769b33fadf45a039741f932672ac2c4f901d7d4aDimitry Ivanov DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx); 73114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (type == R_GENERIC_NONE) { 74114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov continue; 75114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 76114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 78114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov soinfo* lsi = nullptr; 79114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 80114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (sym != 0) { 81114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov sym_name = get_string(symtab_[sym].st_name); 8231b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov const version_info* vi = nullptr; 832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 8431b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { 8531b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov return false; 8631b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov } 872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 8831b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { 8931b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov return false; 902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 92114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (s == nullptr) { 93114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // mips does not support relocation with weak-undefined symbols 94bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", 95bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand sym_name, get_realpath()); 96114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 97114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } else { 98114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // We got a definition. 99114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 100114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 101114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov count_relocation(kRelocSymbol); 102114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 103114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 104114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov switch (type) { 105114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov case R_MIPS_REL32: 106114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#if defined(__LP64__) 107114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // MIPS Elf64_Rel entries contain compound relocations 108114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case 109114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 || 110114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) { 111114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)", 112db3078d97b57224c2c845cefbd46adc77fadfb37Nikola Veljkovic type, static_cast<unsigned>(ELF64_R_TYPE2(rel->r_info)), 113db3078d97b57224c2c845cefbd46adc77fadfb37Nikola Veljkovic static_cast<unsigned>(ELF64_R_TYPE3(rel->r_info)), rel, idx); 114114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 115114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 116114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#endif 117114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov count_relocation(s == nullptr ? kRelocAbsolute : kRelocRelative); 118114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov MARK(rel->r_offset); 119114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc), 120114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*"); 121114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (s != nullptr) { 122114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 123114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } else { 1240373d4f47342e0a6f146af9023a146b0b707442bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += load_bias; 125114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 126114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov break; 127114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov default: 128114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); 129114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 130114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 131114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 132114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return true; 133114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov} 134114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 135f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanovbool soinfo::mips_relocate_got(const VersionTracker& version_tracker, 136f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov const soinfo_list_t& global_group, 13720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const soinfo_list_t& local_group) { 138114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov ElfW(Addr)** got = plt_got_; 139114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (got == nullptr) { 140114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return true; 141114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 142114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 143114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // got[0] is the address of the lazy resolver function. 144114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // got[1] may be used for a GNU extension. 145114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // FIXME: maybe this should be in a separate routine? 146114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if ((flags_ & FLAG_LINKER) == 0) { 147e8c76b7a30b57ec1b9858353bb32bfceda285f4bGoran Ferenc size_t g = 1; 148e8c76b7a30b57ec1b9858353bb32bfceda285f4bGoran Ferenc // Check for the high bit to determine whether to skip got[1] 149114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (reinterpret_cast<intptr_t>(got[g]) < 0) { 150e8c76b7a30b57ec1b9858353bb32bfceda285f4bGoran Ferenc g++; 151114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 152114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // Relocate the local GOT entries. 153114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov for (; g < mips_local_gotno_; g++) { 154114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov got[g] = reinterpret_cast<ElfW(Addr)*>(reinterpret_cast<uintptr_t>(got[g]) + load_bias); 155114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 156114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 157114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 158114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // Now for the global GOT entries... 159114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov got = plt_got_ + mips_local_gotno_; 160f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov for (ElfW(Word) sym = mips_gotsym_; sym < mips_symtabno_; sym++, got++) { 161114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // This is an undefined reference... try to locate it. 162f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov const ElfW(Sym)* local_sym = symtab_ + sym; 163f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov const char* sym_name = get_string(local_sym->st_name); 164114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov soinfo* lsi = nullptr; 1652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 166f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov 167dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov ElfW(Word) st_visibility = (local_sym->st_other & 0x3); 168f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov 169dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov if (st_visibility == STV_DEFAULT) { 170dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov const version_info* vi = nullptr; 171dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov 172dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { 173dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov return false; 174dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov } 175f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov 176dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { 177dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov return false; 178dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov } 179dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov } else if (st_visibility == STV_PROTECTED) { 180dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov if (local_sym->st_value == 0) { 181bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ", 182bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand get_realpath(), sym_name); 183dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov return false; 184dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov } 185dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov s = local_sym; 186dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov lsi = this; 187dbe26fdcc7de503539837467299b96c4a93084ccDmitriy Ivanov } else { 188bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("%s: invalid symbol \"%s\" visibility: 0x%x", 189bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand get_realpath(), sym_name, st_visibility); 1902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 1912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 1922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 193114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov if (s == nullptr) { 194114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // We only allow an undefined symbol if this is a weak reference. 195f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov if (ELF_ST_BIND(local_sym->st_info) != STB_WEAK) { 196bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("%s: cannot locate \"%s\"...", get_realpath(), sym_name); 197114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 198114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 199114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov *got = 0; 200114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } else { 201114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // FIXME: is this sufficient? 202114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov // For reference see NetBSD link loader 203114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy 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 204114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov *got = reinterpret_cast<ElfW(Addr)*>(lsi->resolve_symbol_address(s)); 205114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 206114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov } 207114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return true; 208114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov} 209114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov 210bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#if !defined(__LP64__) 211bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 212bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// Checks for mips32's various floating point abis. 213bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// (Mips64 Android has a single floating point abi and doesn't need any checks) 214bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 215bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// Linux kernel has declarations similar to the following 216bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// in <linux>/arch/mips/include/asm/elf.h, 217bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// but that non-uapi internal header file will never be imported 218bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// into bionic's kernel headers. 219bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 220bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#define PT_MIPS_ABIFLAGS 0x70000003 // is .MIPS.abiflags segment 221bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 222bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sandstruct mips_elf_abiflags_v0 { 223bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand uint16_t version; // version of this structure 224bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand uint8_t isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size; 225bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand uint8_t fp_abi; // mips32 ABI variants for floating point 226dccc40883ace81d203b3ed66944847e55f45da6fDouglas Leung uint32_t isa_ext, ases, flags1, flags2; 227bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand}; 228bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 229bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// Bits of flags1: 230bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#define MIPS_AFL_FLAGS1_ODDSPREG 1 // Uses odd-numbered single-prec fp regs 231bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 232bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand// Some values of fp_abi: via compiler flag: 233e8c76b7a30b57ec1b9858353bb32bfceda285f4bGoran Ferenc#define MIPS_ABI_FP_ANY 0 // Not tagged or not using any ABIs affected by the differences. 234bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#define MIPS_ABI_FP_DOUBLE 1 // -mdouble-float 235bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#define MIPS_ABI_FP_XX 5 // -mfpxx 236bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#define MIPS_ABI_FP_64A 7 // -mips32r* -mfp64 -mno-odd-spreg 237bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 238bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#if __mips_isa_rev >= 5 239bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sandstatic bool mips_fre_mode_on = false; // have set FRE=1 mode for process 240bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#endif 241bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 242bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sandbool soinfo::mips_check_and_adjust_fp_modes() { 243bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand mips_elf_abiflags_v0* abiflags = nullptr; 244bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand int mips_fpabi; 245bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 246bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Find soinfo's optional .MIPS.abiflags segment 247bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand for (size_t i = 0; i<phnum; ++i) { 248bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand const ElfW(Phdr)& ph = phdr[i]; 249bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if (ph.p_type == PT_MIPS_ABIFLAGS) { 250bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if (ph.p_filesz < sizeof (mips_elf_abiflags_v0)) { 251bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("Corrupt PT_MIPS_ABIFLAGS header found \"%s\"", get_realpath()); 252bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand return false; 253bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 254bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand abiflags = reinterpret_cast<mips_elf_abiflags_v0*>(ph.p_vaddr + load_bias); 255bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand break; 256bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 257bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 258bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 259bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // FP ABI-variant compatibility checks for MIPS o32 ABI 260bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if (abiflags == nullptr) { 2612ee458830824c66f5713a6982e6beae8f8a1dc37Goran Jakovljevic // Old compilers lack the new abiflags section. 2622ee458830824c66f5713a6982e6beae8f8a1dc37Goran Jakovljevic // These compilers used -mfp32 -mdouble-float -modd-spreg defaults, 2632ee458830824c66f5713a6982e6beae8f8a1dc37Goran Jakovljevic // ie FP32 aka DOUBLE, using odd-numbered single-prec regs 2642ee458830824c66f5713a6982e6beae8f8a1dc37Goran Jakovljevic mips_fpabi = MIPS_ABI_FP_DOUBLE; 265bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } else { 266bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand mips_fpabi = abiflags->fp_abi; 267bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if ( (abiflags->flags1 & MIPS_AFL_FLAGS1_ODDSPREG) 268bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand && (mips_fpabi == MIPS_ABI_FP_XX || 269bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand mips_fpabi == MIPS_ABI_FP_64A ) ) { 270bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Android supports fewer cases than Linux 271bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("Unsupported odd-single-prec FloatPt reg uses in \"%s\"", 272bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand get_realpath()); 273bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand return false; 274bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 275bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 276bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if (!(mips_fpabi == MIPS_ABI_FP_DOUBLE || 277bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#if __mips_isa_rev >= 5 278bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand mips_fpabi == MIPS_ABI_FP_64A || 279bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#endif 280e8c76b7a30b57ec1b9858353bb32bfceda285f4bGoran Ferenc mips_fpabi == MIPS_ABI_FP_ANY || 281bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand mips_fpabi == MIPS_ABI_FP_XX )) { 282bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("Unsupported MIPS32 FloatPt ABI %d found in \"%s\"", 283bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand mips_fpabi, get_realpath()); 284bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand return false; 285bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 286bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 287bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#if __mips_isa_rev >= 5 288bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Adjust process's FR Emulation mode, if needed 289bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // 290bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // On Mips R5 & R6, Android runs continuously in FR=1 64bit-fpreg mode. 291bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // NDK mips32 apps compiled with old compilers generate FP32 code 292bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // which expects FR=0 32-bit fp registers. 293bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // NDK mips32 apps compiled with newer compilers generate modeless 294bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // FPXX code which runs on both FR=0 and FR=1 modes. 295bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Android itself is compiled in FP64A which requires FR=1 mode. 296bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // FP32, FPXX, and FP64A all interlink okay, without dynamic FR mode 297bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // changes during calls. For details, see 298bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // http://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking 299bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Processes containing FR32 FR=0 code are run via kernel software assist, 300bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // which maps all odd-numbered single-precision reg refs onto the 301bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // upper half of the paired even-numbered double-precision reg. 302bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // FRE=1 triggers traps to the kernel's emulator on every single-precision 303bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // fp op (for both odd and even-numbered registers). 304bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Turning on FRE=1 traps is done at most once per process, simultanously 305bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // for all threads of that process, when dlopen discovers FP32 code. 306bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // The kernel repacks threads' registers when FRE mode is turn on or off. 307bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // These asynchronous adjustments are wrong if any thread was executing 308bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // FPXX code using odd-numbered single-precision regs. 309bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Current Android compilers default to the -mno-oddspreg option, 310bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // and this requirement is checked by Android's dlopen. 311bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // So FRE can always be safely turned on for FP32, anytime. 312bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Deferred enhancement: Allow loading of odd-spreg FPXX modules. 313bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 314bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if (mips_fpabi == MIPS_ABI_FP_DOUBLE && !mips_fre_mode_on) { 315bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Turn on FRE mode, which emulates mode-sensitive FR=0 code on FR=1 316bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // register files, by trapping to kernel on refs to single-precision regs 317bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if (prctl(PR_SET_FP_MODE, PR_FP_MODE_FR|PR_FP_MODE_FRE)) { 318bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_ERR("Kernel or cpu failed to set FRE mode required for running \"%s\"", 319bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand get_realpath()); 320bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand return false; 321bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 322bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand DL_WARN("Using FRE=1 mode to run \"%s\"", get_realpath()); 323bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand mips_fre_mode_on = true; // Avoid future redundant mode-switch calls 324bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // FRE mode is never turned back off. 325bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Deferred enhancement: 326bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Reset FRE mode when dlclose() removes all FP32 modules 327bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 328bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#else 329bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand // Android runs continuously in FR=0 32bit-fpreg mode. 330bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#endif // __mips_isa_rev 331bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand return true; 332bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand} 333bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 334bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#endif // __LP64___ 335