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