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