Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / android_crazy_linker / src / src / crazy_linker_elf_relocations.cpp
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
85 namespace crazy {
86
87 namespace {
88
89 // List of known relocation types the relocator knows about.
90 enum 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.
99 RelocationType 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
166 bool 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
301 bool 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 defined(__arm__) || defined(__aarch64__)
314   if (!ApplyPackedRelocations(error))
315     return false;
316 #endif
317
318   if (relocations_type_ == DT_REL) {
319     if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_),
320                         relocations_size_ / sizeof(ELF::Rel),
321                         symbols,
322                         resolver,
323                         error))
324       return false;
325     if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_),
326                         plt_relocations_size_ / sizeof(ELF::Rel),
327                         symbols,
328                         resolver,
329                         error))
330       return false;
331   }
332
333   if (relocations_type_ == DT_RELA) {
334     if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(relocations_),
335                          relocations_size_ / sizeof(ELF::Rela),
336                          symbols,
337                          resolver,
338                          error))
339       return false;
340     if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(plt_relocations_),
341                          plt_relocations_size_ / sizeof(ELF::Rela),
342                          symbols,
343                          resolver,
344                          error))
345       return false;
346   }
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
366 void ElfRelocations::RegisterPackedRelocations(uint8_t* packed_relocations) {
367   packed_relocations_ = packed_relocations;
368 }
369
370 bool 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
409 bool 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
443 bool 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
468 bool 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
563 bool 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
669 bool 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
724 bool 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
774 bool 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__
825 bool 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
872 void 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
913 void 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
946 void 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
979 void 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