Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "crazy_linker_elf_relocations.h"
      6 
      7 #include <errno.h>
      8 
      9 #include "crazy_linker_debug.h"
     10 #include "crazy_linker_elf_symbols.h"
     11 #include "crazy_linker_elf_view.h"
     12 #include "crazy_linker_error.h"
     13 #include "crazy_linker_util.h"
     14 #include "linker_phdr.h"
     15 
     16 #define DEBUG_RELOCATIONS 0
     17 
     18 #define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__)
     19 #define RLOG_ERRNO(...) LOG_ERRNO_IF(DEBUG_RELOCATIONS, __VA_ARGS__)
     20 
     21 #ifndef DF_SYMBOLIC
     22 #define DF_SYMBOLIC 2
     23 #endif
     24 
     25 #ifndef DF_TEXTREL
     26 #define DF_TEXTREL 4
     27 #endif
     28 
     29 #ifndef DT_FLAGS
     30 #define DT_FLAGS 30
     31 #endif
     32 
     33 // Processor-specific relocation types supported by the linker.
     34 #ifdef __arm__
     35 
     36 /* arm32 relocations */
     37 #define R_ARM_ABS32 2
     38 #define R_ARM_REL32 3
     39 #define R_ARM_GLOB_DAT 21
     40 #define R_ARM_JUMP_SLOT 22
     41 #define R_ARM_COPY 20
     42 #define R_ARM_RELATIVE 23
     43 
     44 #endif  // __arm__
     45 
     46 #ifdef __aarch64__
     47 
     48 /* arm64 relocations */
     49 #define R_AARCH64_ABS64 257
     50 #define R_AARCH64_COPY 1024
     51 #define R_AARCH64_GLOB_DAT 1025
     52 #define R_AARCH64_JUMP_SLOT 1026
     53 #define R_AARCH64_RELATIVE 1027
     54 
     55 #endif  // __aarch64__
     56 
     57 #ifdef __i386__
     58 
     59 /* i386 relocations */
     60 #define R_386_32 1
     61 #define R_386_PC32 2
     62 #define R_386_GLOB_DAT 6
     63 #define R_386_JMP_SLOT 7
     64 #define R_386_RELATIVE 8
     65 
     66 #endif  // __i386__
     67 
     68 namespace crazy {
     69 
     70 namespace {
     71 
     72 // List of known relocation types the relocator knows about.
     73 enum RelocationType {
     74   RELOCATION_TYPE_UNKNOWN = 0,
     75   RELOCATION_TYPE_ABSOLUTE = 1,
     76   RELOCATION_TYPE_RELATIVE = 2,
     77   RELOCATION_TYPE_PC_RELATIVE = 3,
     78   RELOCATION_TYPE_COPY = 4,
     79 };
     80 
     81 // Convert an ELF relocation type info a RelocationType value.
     82 RelocationType GetRelocationType(ELF::Word r_type) {
     83   switch (r_type) {
     84 #ifdef __arm__
     85     case R_ARM_JUMP_SLOT:
     86     case R_ARM_GLOB_DAT:
     87     case R_ARM_ABS32:
     88       return RELOCATION_TYPE_ABSOLUTE;
     89 
     90     case R_ARM_REL32:
     91     case R_ARM_RELATIVE:
     92       return RELOCATION_TYPE_RELATIVE;
     93 
     94     case R_ARM_COPY:
     95       return RELOCATION_TYPE_COPY;
     96 #endif
     97 
     98 #ifdef __aarch64__
     99     case R_AARCH64_JUMP_SLOT:
    100     case R_AARCH64_GLOB_DAT:
    101     case R_AARCH64_ABS64:
    102       return RELOCATION_TYPE_ABSOLUTE;
    103 
    104     case R_AARCH64_RELATIVE:
    105       return RELOCATION_TYPE_RELATIVE;
    106 
    107     case R_AARCH64_COPY:
    108       return RELOCATION_TYPE_COPY;
    109 #endif
    110 
    111 #ifdef __i386__
    112     case R_386_JMP_SLOT:
    113     case R_386_GLOB_DAT:
    114     case R_386_32:
    115       return RELOCATION_TYPE_ABSOLUTE;
    116 
    117     case R_386_RELATIVE:
    118       return RELOCATION_TYPE_RELATIVE;
    119 
    120     case R_386_PC32:
    121       return RELOCATION_TYPE_PC_RELATIVE;
    122 #endif
    123 
    124 #ifdef __mips__
    125     case R_MIPS_REL32:
    126       return RELOCATION_TYPE_RELATIVE;
    127 #endif
    128 
    129     default:
    130       return RELOCATION_TYPE_UNKNOWN;
    131   }
    132 }
    133 
    134 }  // namespace
    135 
    136 bool ElfRelocations::Init(const ElfView* view, Error* error) {
    137   // Save these for later.
    138   phdr_ = view->phdr();
    139   phdr_count_ = view->phdr_count();
    140   load_bias_ = view->load_bias();
    141 
    142   // We handle only Rel or Rela, but not both. If DT_RELA or DT_RELASZ
    143   // then we require DT_PLTREL to agree.
    144   bool has_rela_relocations = false;
    145   bool has_rel_relocations = false;
    146 
    147   // Parse the dynamic table.
    148   ElfView::DynamicIterator dyn(view);
    149   for (; dyn.HasNext(); dyn.GetNext()) {
    150     ELF::Addr dyn_value = dyn.GetValue();
    151     uintptr_t dyn_addr = dyn.GetAddress(view->load_bias());
    152 
    153     const ELF::Addr tag = dyn.GetTag();
    154     switch (tag) {
    155       case DT_PLTREL:
    156         RLOG("  DT_PLTREL value=%d\n", dyn_value);
    157         if (dyn_value != DT_REL && dyn_value != DT_RELA) {
    158           *error = "Invalid DT_PLTREL value in dynamic section";
    159           return false;
    160         }
    161         relocations_type_ = dyn_value;
    162         break;
    163       case DT_JMPREL:
    164         RLOG("  DT_JMPREL addr=%p\n", dyn_addr);
    165         plt_relocations_ = dyn_addr;
    166         break;
    167       case DT_PLTRELSZ:
    168         plt_relocations_size_ = dyn_value;
    169         RLOG("  DT_PLTRELSZ size=%d\n", dyn_value);
    170         break;
    171       case DT_RELA:
    172       case DT_REL:
    173         RLOG("  %s addr=%p\n",
    174              (tag == DT_RELA) ? "DT_RELA" : "DT_REL",
    175              dyn_addr);
    176         if (relocations_) {
    177           *error = "Unsupported DT_RELA/DT_REL combination in dynamic section";
    178           return false;
    179         }
    180         relocations_ = dyn_addr;
    181         if (tag == DT_RELA)
    182           has_rela_relocations = true;
    183         else
    184           has_rel_relocations = true;
    185         break;
    186       case DT_RELASZ:
    187       case DT_RELSZ:
    188         RLOG("  %s size=%d\n",
    189              (tag == DT_RELASZ) ? "DT_RELASZ" : "DT_RELSZ",
    190              dyn_addr);
    191         if (relocations_size_) {
    192           *error = "Unsupported DT_RELASZ/DT_RELSZ combination in dyn section";
    193           return false;
    194         }
    195         relocations_size_ = dyn_value;
    196         if (tag == DT_RELASZ)
    197           has_rela_relocations = true;
    198         else
    199           has_rel_relocations = true;
    200         break;
    201       case DT_PLTGOT:
    202         // Only used on MIPS currently. Could also be used on other platforms
    203         // when lazy binding (i.e. RTLD_LAZY) is implemented.
    204         RLOG("  DT_PLTGOT addr=%p\n", dyn_addr);
    205         plt_got_ = reinterpret_cast<ELF::Addr*>(dyn_addr);
    206         break;
    207       case DT_TEXTREL:
    208         RLOG("  DT_TEXTREL\n");
    209         has_text_relocations_ = true;
    210         break;
    211       case DT_SYMBOLIC:
    212         RLOG("  DT_SYMBOLIC\n");
    213         has_symbolic_ = true;
    214         break;
    215       case DT_FLAGS:
    216         if (dyn_value & DF_TEXTREL)
    217           has_text_relocations_ = true;
    218         if (dyn_value & DF_SYMBOLIC)
    219           has_symbolic_ = true;
    220         RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n",
    221              has_text_relocations_ ? "true" : "false",
    222              has_symbolic_ ? "true" : "false");
    223         break;
    224 #if defined(__mips__)
    225       case DT_MIPS_SYMTABNO:
    226         RLOG("  DT_MIPS_SYMTABNO value=%d\n", dyn_value);
    227         mips_symtab_count_ = dyn_value;
    228         break;
    229 
    230       case DT_MIPS_LOCAL_GOTNO:
    231         RLOG("  DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value);
    232         mips_local_got_count_ = dyn_value;
    233         break;
    234 
    235       case DT_MIPS_GOTSYM:
    236         RLOG("  DT_MIPS_GOTSYM value=%d\n", dyn_value);
    237         mips_gotsym_ = dyn_value;
    238         break;
    239 #endif
    240       default:
    241         ;
    242     }
    243   }
    244 
    245   if (relocations_type_ != DT_REL && relocations_type_ != DT_RELA) {
    246     *error = "Unsupported or missing DT_PLTREL in dynamic section";
    247     return false;
    248   }
    249 
    250   if (relocations_type_ == DT_REL && has_rela_relocations) {
    251     *error = "Found DT_RELA in dyn section, but DT_PLTREL is DT_REL";
    252     return false;
    253   }
    254   if (relocations_type_ == DT_RELA && has_rel_relocations) {
    255     *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA";
    256     return false;
    257   }
    258 
    259   return true;
    260 }
    261 
    262 bool ElfRelocations::ApplyAll(const ElfSymbols* symbols,
    263                               SymbolResolver* resolver,
    264                               Error* error) {
    265   LOG("%s: Enter\n", __FUNCTION__);
    266 
    267   if (has_text_relocations_) {
    268     if (phdr_table_unprotect_segments(phdr_, phdr_count_, load_bias_) < 0) {
    269       error->Format("Can't unprotect loadable segments: %s", strerror(errno));
    270       return false;
    271     }
    272   }
    273 
    274   if (relocations_type_ == DT_REL) {
    275     if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_),
    276                         plt_relocations_size_ / sizeof(ELF::Rel),
    277                         symbols,
    278                         resolver,
    279                         error))
    280       return false;
    281     if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_),
    282                         relocations_size_ / sizeof(ELF::Rel),
    283                         symbols,
    284                         resolver,
    285                         error))
    286       return false;
    287   }
    288 
    289   else if (relocations_type_ == DT_RELA) {
    290     if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(plt_relocations_),
    291                          plt_relocations_size_ / sizeof(ELF::Rela),
    292                          symbols,
    293                          resolver,
    294                          error))
    295       return false;
    296     if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(relocations_),
    297                          relocations_size_ / sizeof(ELF::Rela),
    298                          symbols,
    299                          resolver,
    300                          error))
    301       return false;
    302   }
    303 
    304 #ifdef __mips__
    305   if (!RelocateMipsGot(symbols, resolver, error))
    306     return false;
    307 #endif
    308 
    309   if (has_text_relocations_) {
    310     if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) {
    311       error->Format("Can't reprotect loadable segments: %s", strerror(errno));
    312       return false;
    313     }
    314   }
    315 
    316   LOG("%s: Done\n", __FUNCTION__);
    317   return true;
    318 }
    319 
    320 bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela,
    321                                     ELF::Addr sym_addr,
    322                                     bool resolved CRAZY_UNUSED,
    323                                     Error* error) {
    324   const ELF::Word rela_type = ELF_R_TYPE(rela->r_info);
    325   const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info);
    326   const ELF::Sword CRAZY_UNUSED addend = rela->r_addend;
    327 
    328   const ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_);
    329 
    330   RLOG("  rela reloc=%p offset=%p type=%d addend=%p\n",
    331        reloc,
    332        rela->r_offset,
    333        rela_type,
    334        addend);
    335 
    336   // Apply the relocation.
    337   ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc);
    338   switch (rela_type) {
    339 #ifdef __aarch64__
    340     case R_AARCH64_JUMP_SLOT:
    341       RLOG("  R_AARCH64_JUMP_SLOT target=%p addr=%p\n",
    342            target,
    343            sym_addr + addend);
    344       *target = sym_addr + addend;
    345       break;
    346 
    347     case R_AARCH64_GLOB_DAT:
    348       RLOG("  R_AARCH64_GLOB_DAT target=%p addr=%p\n",
    349            target,
    350            sym_addr + addend);
    351       *target = sym_addr + addend;
    352       break;
    353 
    354     case R_AARCH64_ABS64:
    355       RLOG("  R_AARCH64_ABS64 target=%p (%p) addr=%p\n",
    356            target,
    357            *target,
    358            sym_addr + addend);
    359       *target += sym_addr + addend;
    360       break;
    361 
    362     case R_AARCH64_RELATIVE:
    363       RLOG("  R_AARCH64_RELATIVE target=%p (%p) bias=%p\n",
    364            target,
    365            *target,
    366            load_bias_ + addend);
    367       if (__builtin_expect(rela_symbol, 0)) {
    368         *error = "Invalid relative relocation with symbol";
    369         return false;
    370       }
    371       *target = load_bias_ + addend;
    372       break;
    373 
    374     case R_AARCH64_COPY:
    375       // NOTE: These relocations are forbidden in shared libraries.
    376       RLOG("  R_AARCH64_COPY\n");
    377       *error = "Invalid R_AARCH64_COPY relocation in shared library";
    378       return false;
    379 #endif  // __aarch64__
    380 
    381     default:
    382       error->Format("Invalid relocation type (%d)", rela_type);
    383       return false;
    384   }
    385 
    386   return true;
    387 }
    388 
    389 bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel,
    390                                    ELF::Addr sym_addr,
    391                                    bool resolved CRAZY_UNUSED,
    392                                    Error* error) {
    393   const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
    394   const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info);
    395 
    396   const ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
    397 
    398   RLOG("  rel reloc=%p offset=%p type=%d\n", reloc, rel->r_offset, rel_type);
    399 
    400   // Apply the relocation.
    401   ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc);
    402   switch (rel_type) {
    403 #ifdef __arm__
    404     case R_ARM_JUMP_SLOT:
    405       RLOG("  R_ARM_JUMP_SLOT target=%p addr=%p\n", target, sym_addr);
    406       *target = sym_addr;
    407       break;
    408 
    409     case R_ARM_GLOB_DAT:
    410       RLOG("  R_ARM_GLOB_DAT target=%p addr=%p\n", target, sym_addr);
    411       *target = sym_addr;
    412       break;
    413 
    414     case R_ARM_ABS32:
    415       RLOG("  R_ARM_ABS32 target=%p (%p) addr=%p\n",
    416            target,
    417            *target,
    418            sym_addr);
    419       *target += sym_addr;
    420       break;
    421 
    422     case R_ARM_REL32:
    423       RLOG("  R_ARM_REL32 target=%p (%p) addr=%p offset=%p\n",
    424            target,
    425            *target,
    426            sym_addr,
    427            rel->r_offset);
    428       *target += sym_addr - rel->r_offset;
    429       break;
    430 
    431     case R_ARM_RELATIVE:
    432       RLOG("  R_ARM_RELATIVE target=%p (%p) bias=%p\n",
    433            target,
    434            *target,
    435            load_bias_);
    436       if (__builtin_expect(rel_symbol, 0)) {
    437         *error = "Invalid relative relocation with symbol";
    438         return false;
    439       }
    440       *target += load_bias_;
    441       break;
    442 
    443     case R_ARM_COPY:
    444       // NOTE: These relocations are forbidden in shared libraries.
    445       // The Android linker has special code to deal with this, which
    446       // is not needed here.
    447       RLOG("  R_ARM_COPY\n");
    448       *error = "Invalid R_ARM_COPY relocation in shared library";
    449       return false;
    450 #endif  // __arm__
    451 
    452 #ifdef __i386__
    453     case R_386_JMP_SLOT:
    454       *target = sym_addr;
    455       break;
    456 
    457     case R_386_GLOB_DAT:
    458       *target = sym_addr;
    459       break;
    460 
    461     case R_386_RELATIVE:
    462       if (rel_symbol) {
    463         *error = "Invalid relative relocation with symbol";
    464         return false;
    465       }
    466       *target += load_bias_;
    467       break;
    468 
    469     case R_386_32:
    470       *target += sym_addr;
    471       break;
    472 
    473     case R_386_PC32:
    474       *target += (sym_addr - reloc);
    475       break;
    476 #endif  // __i386__
    477 
    478 #ifdef __mips__
    479     case R_MIPS_REL32:
    480       if (resolved)
    481         *target += sym_addr;
    482       else
    483         *target += load_bias_;
    484       break;
    485 #endif  // __mips__
    486 
    487     default:
    488       error->Format("Invalid relocation type (%d)", rel_type);
    489       return false;
    490   }
    491 
    492   return true;
    493 }
    494 
    495 bool ElfRelocations::ResolveSymbol(ELF::Word rel_type,
    496                                    ELF::Word rel_symbol,
    497                                    const ElfSymbols* symbols,
    498                                    SymbolResolver* resolver,
    499                                    ELF::Addr reloc,
    500                                    ELF::Addr* sym_addr,
    501                                    Error* error) {
    502   const char* sym_name = symbols->LookupNameById(rel_symbol);
    503   RLOG("    symbol name='%s'\n", sym_name);
    504   void* address = resolver->Lookup(sym_name);
    505 
    506   if (address) {
    507     // The symbol was found, so compute its address.
    508     RLOG("%s: symbol %s resolved to %p\n", __FUNCTION__, sym_name, address);
    509     *sym_addr = reinterpret_cast<ELF::Addr>(address);
    510     return true;
    511   }
    512 
    513   // The symbol was not found. Normally this is an error except
    514   // if this is a weak reference.
    515   if (!symbols->IsWeakById(rel_symbol)) {
    516     error->Format("Could not find symbol '%s'", sym_name);
    517     return false;
    518   }
    519 
    520   RLOG("%s: weak reference to unresolved symbol %s\n", __FUNCTION__, sym_name);
    521 
    522   // IHI0044C AAELF 4.5.1.1:
    523   // Libraries are not searched to resolve weak references.
    524   // It is not an error for a weak reference to remain
    525   // unsatisfied.
    526   //
    527   // During linking, the value of an undefined weak reference is:
    528   // - Zero if the relocation type is absolute
    529   // - The address of the place if the relocation is pc-relative
    530   // - The address of nominal base address if the relocation
    531   //   type is base-relative.
    532   RelocationType r = GetRelocationType(rel_type);
    533   if (r == RELOCATION_TYPE_ABSOLUTE || r == RELOCATION_TYPE_RELATIVE) {
    534     *sym_addr = 0;
    535     return true;
    536   }
    537 
    538   if (r == RELOCATION_TYPE_PC_RELATIVE) {
    539     *sym_addr = reloc;
    540     return true;
    541   }
    542 
    543   error->Format(
    544       "Invalid weak relocation type (%d) for unknown symbol '%s'",
    545       r,
    546       sym_name);
    547   return false;
    548 }
    549 
    550 bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel,
    551                                     size_t rel_count,
    552                                     const ElfSymbols* symbols,
    553                                     SymbolResolver* resolver,
    554                                     Error* error) {
    555   RLOG("%s: rel=%p rel_count=%d\n", __FUNCTION__, rel, rel_count);
    556 
    557   if (!rel)
    558     return true;
    559 
    560   for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) {
    561     const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
    562     const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
    563 
    564     ELF::Addr sym_addr = 0;
    565     ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
    566     RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n",
    567          rel_n + 1,
    568          rel_count,
    569          reloc,
    570          rel->r_offset,
    571          rel_type,
    572          rel_symbol);
    573 
    574     if (rel_type == 0)
    575       continue;
    576 
    577     bool resolved = false;
    578 
    579     // If this is a symbolic relocation, compute the symbol's address.
    580     if (__builtin_expect(rel_symbol != 0, 0)) {
    581       resolved = ResolveSymbol(rel_type,
    582                                rel_symbol,
    583                                symbols,
    584                                resolver,
    585                                reloc,
    586                                &sym_addr,
    587                                error);
    588     }
    589 
    590     if (!ApplyRelReloc(rel, sym_addr, resolved, error))
    591       return false;
    592   }
    593 
    594   return true;
    595 }
    596 
    597 bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela,
    598                                      size_t rela_count,
    599                                      const ElfSymbols* symbols,
    600                                      SymbolResolver* resolver,
    601                                      Error* error) {
    602   RLOG("%s: rela=%p rela_count=%d\n", __FUNCTION__, rela, rela_count);
    603 
    604   if (!rela)
    605     return true;
    606 
    607   for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) {
    608     const ELF::Word rel_type = ELF_R_TYPE(rela->r_info);
    609     const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info);
    610 
    611     ELF::Addr sym_addr = 0;
    612     ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_);
    613     RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n",
    614          rel_n + 1,
    615          rela_count,
    616          reloc,
    617          rela->r_offset,
    618          rel_type,
    619          rel_symbol);
    620 
    621     if (rel_type == 0)
    622       continue;
    623 
    624     bool resolved = false;
    625 
    626     // If this is a symbolic relocation, compute the symbol's address.
    627     if (__builtin_expect(rel_symbol != 0, 0)) {
    628       resolved = ResolveSymbol(rel_type,
    629                                rel_symbol,
    630                                symbols,
    631                                resolver,
    632                                reloc,
    633                                &sym_addr,
    634                                error);
    635     }
    636 
    637     if (!ApplyRelaReloc(rela, sym_addr, resolved, error))
    638       return false;
    639   }
    640 
    641   return true;
    642 }
    643 
    644 #ifdef __mips__
    645 bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols,
    646                                      SymbolResolver* resolver,
    647                                      Error* error) {
    648   if (!plt_got_)
    649     return true;
    650 
    651   // Handle the local GOT entries.
    652   // This mimics what the system linker does.
    653   // Note from the system linker:
    654   // got[0]: lazy resolver function address.
    655   // got[1]: may be used for a GNU extension.
    656   // Set it to a recognizable address in case someone calls it
    657   // (should be _rtld_bind_start).
    658   ELF::Addr* got = plt_got_;
    659   got[0] = 0xdeadbeef;
    660   if (got[1] & 0x80000000)
    661     got[1] = 0xdeadbeef;
    662 
    663   for (ELF::Addr n = 2; n < mips_local_got_count_; ++n)
    664     got[n] += load_bias_;
    665 
    666   // Handle the global GOT entries.
    667   got += mips_local_got_count_;
    668   for (size_t idx = mips_gotsym_; idx < mips_symtab_count_; idx++, got++) {
    669     const char* sym_name = symbols->LookupNameById(idx);
    670     void* sym_addr = resolver->Lookup(sym_name);
    671     if (sym_addr) {
    672       // Found symbol, update GOT entry.
    673       *got = reinterpret_cast<ELF::Addr>(sym_addr);
    674       continue;
    675     }
    676 
    677     if (symbols->IsWeakById(idx)) {
    678       // Undefined symbols are only ok if this is a weak reference.
    679       // Update GOT entry to 0 though.
    680       *got = 0;
    681       continue;
    682     }
    683 
    684     error->Format("Cannot locate symbol %s", sym_name);
    685     return false;
    686   }
    687 
    688   return true;
    689 }
    690 #endif  // __mips__
    691 
    692 void ElfRelocations::AdjustRelocation(ELF::Word rel_type,
    693                                       ELF::Addr src_reloc,
    694                                       size_t dst_delta,
    695                                       size_t map_delta) {
    696   ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(src_reloc + dst_delta);
    697 
    698   switch (rel_type) {
    699 #ifdef __arm__
    700     case R_ARM_RELATIVE:
    701       *dst_ptr += map_delta;
    702       break;
    703 #endif  // __arm__
    704 
    705 #ifdef __aarch64__
    706     case R_AARCH64_RELATIVE:
    707       *dst_ptr += map_delta;
    708       break;
    709 #endif  // __aarch64__
    710 
    711 #ifdef __i386__
    712     case R_386_RELATIVE:
    713       *dst_ptr += map_delta;
    714       break;
    715 #endif
    716 
    717 #ifdef __mips__
    718     case R_MIPS_REL32:
    719       *dst_ptr += map_delta;
    720       break;
    721 #endif
    722     default:
    723       ;
    724   }
    725 }
    726 
    727 void ElfRelocations::RelocateRela(size_t src_addr,
    728                                   size_t dst_addr,
    729                                   size_t map_addr,
    730                                   size_t size) {
    731   // Add this value to each source address to get the corresponding
    732   // destination address.
    733   const size_t dst_delta = dst_addr - src_addr;
    734   const size_t map_delta = map_addr - src_addr;
    735 
    736   // Ignore PLT relocations, which all target symbols (ignored here).
    737   const ELF::Rela* rel = reinterpret_cast<ELF::Rela*>(relocations_);
    738   const size_t relocations_count = relocations_size_ / sizeof(ELF::Rela);
    739   const ELF::Rela* rel_limit = rel + relocations_count;
    740 
    741   for (; rel < rel_limit; ++rel) {
    742     const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
    743     const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
    744     ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
    745 
    746     if (rel_type == 0 || rel_symbol != 0) {
    747       // Ignore empty and symbolic relocations
    748       continue;
    749     }
    750 
    751     if (src_reloc < src_addr || src_reloc >= src_addr + size) {
    752       // Ignore entries that don't relocate addresses inside the source section.
    753       continue;
    754     }
    755 
    756     AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta);
    757   }
    758 }
    759 
    760 void ElfRelocations::RelocateRel(size_t src_addr,
    761                                  size_t dst_addr,
    762                                  size_t map_addr,
    763                                  size_t size) {
    764   // Add this value to each source address to get the corresponding
    765   // destination address.
    766   const size_t dst_delta = dst_addr - src_addr;
    767   const size_t map_delta = map_addr - src_addr;
    768 
    769   // Ignore PLT relocations, which all target symbols (ignored here).
    770   const ELF::Rel* rel = reinterpret_cast<ELF::Rel*>(relocations_);
    771   const size_t relocations_count = relocations_size_ / sizeof(ELF::Rel);
    772   const ELF::Rel* rel_limit = rel + relocations_count;
    773 
    774   for (; rel < rel_limit; ++rel) {
    775     const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
    776     const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
    777     ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
    778 
    779     if (rel_type == 0 || rel_symbol != 0) {
    780       // Ignore empty and symbolic relocations
    781       continue;
    782     }
    783 
    784     if (src_reloc < src_addr || src_reloc >= src_addr + size) {
    785       // Ignore entries that don't relocate addresses inside the source section.
    786       continue;
    787     }
    788 
    789     AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta);
    790   }
    791 }
    792 
    793 void ElfRelocations::CopyAndRelocate(size_t src_addr,
    794                                      size_t dst_addr,
    795                                      size_t map_addr,
    796                                      size_t size) {
    797   // First, a straight copy.
    798   ::memcpy(reinterpret_cast<void*>(dst_addr),
    799            reinterpret_cast<void*>(src_addr),
    800            size);
    801 
    802   // Relocate relocations.
    803   if (relocations_type_ == DT_REL)
    804     RelocateRel(src_addr, dst_addr, map_addr, size);
    805 
    806   else if (relocations_type_ == DT_RELA)
    807     RelocateRela(src_addr, dst_addr, map_addr, size);
    808 
    809 #ifdef __mips__
    810   // Add this value to each source address to get the corresponding
    811   // destination address.
    812   const size_t dst_delta = dst_addr - src_addr;
    813   const size_t map_delta = map_addr - src_addr;
    814 
    815   // Only relocate local GOT entries.
    816   ELF::Addr* got = plt_got_;
    817   if (got) {
    818     for (ELF::Addr n = 2; n < mips_local_got_count_; ++n) {
    819       size_t got_addr = reinterpret_cast<size_t>(&got[n]);
    820       if (got_addr < src_addr || got_addr >= src_addr + size)
    821         continue;
    822       ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(got_addr + dst_delta);
    823       *dst_ptr += map_delta;
    824     }
    825   }
    826 #endif
    827 }
    828 
    829 }  // namespace crazy
    830