Index: third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp |
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp |
index bcd2bea118b88b56aba4a6397e21816b9753c393..79e58bf1ca3beaa987d21b58a16330cacd521299 100644 |
--- a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp |
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp |
@@ -33,6 +33,7 @@ |
// Processor-specific relocation types supported by the linker. |
#ifdef __arm__ |
+/* arm32 relocations */ |
#define R_ARM_ABS32 2 |
#define R_ARM_REL32 3 |
#define R_ARM_GLOB_DAT 21 |
@@ -42,6 +43,17 @@ |
#endif // __arm__ |
+#ifdef __aarch64__ |
+ |
+/* arm64 relocations */ |
+#define R_AARCH64_ABS64 257 |
+#define R_AARCH64_COPY 1024 |
+#define R_AARCH64_GLOB_DAT 1025 |
+#define R_AARCH64_JUMP_SLOT 1026 |
+#define R_AARCH64_RELATIVE 1027 |
+ |
Anton
2014/06/11 15:31:54
Some pointers to documentation would be helpful, w
|
+#endif // __aarch64__ |
+ |
#ifdef __i386__ |
/* i386 relocations */ |
@@ -67,7 +79,7 @@ enum RelocationType { |
}; |
// Convert an ELF relocation type info a RelocationType value. |
-RelocationType GetRelocationType(unsigned r_type) { |
+RelocationType GetRelocationType(ELF::Word r_type) { |
switch (r_type) { |
#ifdef __arm__ |
case R_ARM_JUMP_SLOT: |
@@ -83,6 +95,19 @@ RelocationType GetRelocationType(unsigned r_type) { |
return RELOCATION_TYPE_COPY; |
#endif |
+#ifdef __aarch64__ |
+ case R_AARCH64_JUMP_SLOT: |
+ case R_AARCH64_GLOB_DAT: |
+ case R_AARCH64_ABS64: |
+ return RELOCATION_TYPE_ABSOLUTE; |
+ |
+ case R_AARCH64_RELATIVE: |
+ return RELOCATION_TYPE_RELATIVE; |
+ |
+ case R_AARCH64_COPY: |
+ return RELOCATION_TYPE_COPY; |
+#endif |
+ |
#ifdef __i386__ |
case R_386_JMP_SLOT: |
case R_386_GLOB_DAT: |
@@ -114,49 +139,71 @@ bool ElfRelocations::Init(const ElfView* view, Error* error) { |
phdr_count_ = view->phdr_count(); |
load_bias_ = view->load_bias(); |
+ // We handle only Rel or Rela, but not both. If DT_RELA or DT_RELASZ |
+ // then we require DT_PLTREL to agree. |
+ bool has_rela_relocations = false; |
+ bool has_rel_relocations = false; |
+ |
// Parse the dynamic table. |
ElfView::DynamicIterator dyn(view); |
for (; dyn.HasNext(); dyn.GetNext()) { |
ELF::Addr dyn_value = dyn.GetValue(); |
uintptr_t dyn_addr = dyn.GetAddress(view->load_bias()); |
- switch (dyn.GetTag()) { |
+ const ELF::Addr tag = dyn.GetTag(); |
+ switch (tag) { |
case DT_PLTREL: |
- // NOTE: Yes, there is nothing to record here, the content of |
- // plt_rel_ will come from DT_JMPREL instead. |
- RLOG(" DT_PLTREL\n"); |
- if (dyn_value != DT_REL) { |
- *error = "Unsupported DT_RELA entry in dynamic section"; |
+ RLOG(" DT_PLTREL value=%d\n", dyn_value); |
+ if (dyn_value != DT_REL && dyn_value != DT_RELA) { |
+ *error = "Invalid DT_PLTREL value in dynamic section"; |
return false; |
} |
+ relocations_type_ = dyn_value; |
break; |
case DT_JMPREL: |
RLOG(" DT_JMPREL addr=%p\n", dyn_addr); |
- plt_relocations_ = reinterpret_cast<ELF::Rel*>(dyn_addr); |
+ plt_relocations_ = dyn_addr; |
break; |
case DT_PLTRELSZ: |
- plt_relocations_count_ = dyn_value / sizeof(ELF::Rel); |
- RLOG(" DT_PLTRELSZ size=%d count=%d\n", |
- dyn_value, |
- plt_relocations_count_); |
+ plt_relocations_size_ = dyn_value; |
+ RLOG(" DT_PLTRELSZ size=%d\n", dyn_value); |
break; |
+ case DT_RELA: |
case DT_REL: |
- RLOG(" DT_REL addr=%p\n", dyn_addr); |
- relocations_ = reinterpret_cast<ELF::Rel*>(dyn_addr); |
+ RLOG(" %s addr=%p\n", |
+ (tag == DT_RELA) ? "DT_RELA" : "DT_REL", |
+ dyn_addr); |
+ if (relocations_) { |
+ *error = "Unsupported DT_RELA/DT_REL combination in dynamic section"; |
+ return false; |
+ } |
+ relocations_ = dyn_addr; |
+ if (tag == DT_RELA) |
+ has_rela_relocations = true; |
+ else |
+ has_rel_relocations = true; |
break; |
+ case DT_RELASZ: |
case DT_RELSZ: |
- relocations_count_ = dyn_value / sizeof(ELF::Rel); |
- RLOG(" DT_RELSZ size=%d count=%d\n", dyn_value, relocations_count_); |
+ RLOG(" %s size=%d\n", |
+ (tag == DT_RELASZ) ? "DT_RELASZ" : "DT_RELSZ", |
+ dyn_addr); |
+ if (relocations_size_) { |
Anton
2014/06/11 15:31:53
Google style is to say: relocations_size != 0 as i
|
+ *error = "Unsupported DT_RELASZ/DT_RELSZ combination in dyn section"; |
+ return false; |
+ } |
+ relocations_size_ = dyn_value; |
+ if (tag == DT_RELASZ) |
+ has_rela_relocations = true; |
+ else |
+ has_rel_relocations = true; |
break; |
case DT_PLTGOT: |
// Only used on MIPS currently. Could also be used on other platforms |
// when lazy binding (i.e. RTLD_LAZY) is implemented. |
RLOG(" DT_PLTGOT addr=%p\n", dyn_addr); |
- plt_got_ = reinterpret_cast<uintptr_t*>(dyn_addr); |
+ plt_got_ = reinterpret_cast<ELF::Addr*>(dyn_addr); |
break; |
- case DT_RELA: |
- *error = "Unsupported DT_RELA entry in dynamic section"; |
- return false; |
case DT_TEXTREL: |
RLOG(" DT_TEXTREL\n"); |
has_text_relocations_ = true; |
@@ -195,6 +242,20 @@ bool ElfRelocations::Init(const ElfView* view, Error* error) { |
} |
} |
+ if (relocations_type_ != DT_REL && relocations_type_ != DT_RELA) { |
+ *error = "Unsupported or missing DT_PLTREL in dynamic section"; |
+ return false; |
+ } |
+ |
+ if (relocations_type_ == DT_REL && has_rela_relocations) { |
+ *error = "Found DT_RELA in dyn section, but DT_PLTREL is DT_REL"; |
+ return false; |
+ } |
Anton
2014/06/11 15:31:54
Inconsistent spacing L249 v L253.
|
+ if (relocations_type_ == DT_RELA && has_rel_relocations) { |
+ *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA"; |
+ return false; |
+ } |
+ |
return true; |
} |
@@ -210,14 +271,34 @@ bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, |
} |
} |
- if (!ApplyRelocs(plt_relocations_, |
- plt_relocations_count_, |
- symbols, |
- resolver, |
- error) || |
- !ApplyRelocs( |
- relocations_, relocations_count_, symbols, resolver, error)) { |
- return false; |
+ if (relocations_type_ == DT_REL) { |
+ if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_), |
+ plt_relocations_size_ / sizeof(ELF::Rel), |
+ symbols, |
+ resolver, |
+ error)) |
+ return false; |
+ if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_), |
+ relocations_size_ / sizeof(ELF::Rel), |
+ symbols, |
+ resolver, |
+ error)) |
+ return false; |
+ } |
+ |
Anton
2014/06/11 15:31:54
} else if (..) {
|
+ else if (relocations_type_ == DT_RELA) { |
+ if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(plt_relocations_), |
+ plt_relocations_size_ / sizeof(ELF::Rela), |
+ symbols, |
+ resolver, |
+ error)) |
+ return false; |
+ if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(relocations_), |
+ relocations_size_ / sizeof(ELF::Rela), |
+ symbols, |
+ resolver, |
+ error)) |
+ return false; |
} |
#ifdef __mips__ |
@@ -236,19 +317,249 @@ bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, |
return true; |
} |
-bool ElfRelocations::ApplyRelocs(const ELF::Rel* rel, |
- size_t rel_count, |
- const ElfSymbols* symbols, |
- SymbolResolver* resolver, |
- Error* error) { |
+bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela, |
+ ELF::Addr sym_addr, |
+ bool resolved CRAZY_UNUSED, |
+ Error* error) { |
+ const ELF::Word rela_type = ELF_R_TYPE(rela->r_info); |
+ const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info); |
+ const ELF::Sword CRAZY_UNUSED addend = rela->r_addend; |
Anton
2014/06/11 15:31:54
So the UNUSED applies to the non-aarch64. I assume
|
+ |
+ const ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); |
+ |
+ RLOG(" rela reloc=%p offset=%p type=%d addend=%p\n", |
+ reloc, |
+ rela->r_offset, |
+ rela_type, |
+ addend); |
+ |
+ // Apply the relocation. |
+ ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc); |
+ switch (rela_type) { |
+#ifdef __aarch64__ |
+ case R_AARCH64_JUMP_SLOT: |
+ RLOG(" R_AARCH64_JUMP_SLOT target=%p addr=%p\n", |
+ target, |
+ sym_addr + addend); |
+ *target = sym_addr + addend; |
+ break; |
+ |
+ case R_AARCH64_GLOB_DAT: |
+ RLOG(" R_AARCH64_GLOB_DAT target=%p addr=%p\n", |
+ target, |
+ sym_addr + addend); |
+ *target = sym_addr + addend; |
+ break; |
Anton
2014/06/11 15:31:54
Its the same, is that right?
|
+ |
+ case R_AARCH64_ABS64: |
+ RLOG(" R_AARCH64_ABS64 target=%p (%p) addr=%p\n", |
+ target, |
+ *target, |
+ sym_addr + addend); |
+ *target += sym_addr + addend; |
+ break; |
+ |
+ case R_AARCH64_RELATIVE: |
+ RLOG(" R_AARCH64_RELATIVE target=%p (%p) bias=%p\n", |
+ target, |
+ *target, |
+ load_bias_ + addend); |
+ if (__builtin_expect(rela_symbol, 0)) { |
+ *error = "Invalid relative relocation with symbol"; |
+ return false; |
+ } |
+ *target = load_bias_ + addend; |
+ break; |
+ |
+ case R_AARCH64_COPY: |
+ // NOTE: These relocations are forbidden in shared libraries. |
+ RLOG(" R_AARCH64_COPY\n"); |
+ *error = "Invalid R_AARCH64_COPY relocation in shared library"; |
+ return false; |
+#endif // __aarch64__ |
+ |
+ default: |
+ error->Format("Invalid relocation type (%d)", rela_type); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel, |
+ ELF::Addr sym_addr, |
+ bool resolved CRAZY_UNUSED, |
+ Error* error) { |
+ const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); |
+ const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info); |
+ |
+ const ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); |
+ |
+ RLOG(" rel reloc=%p offset=%p type=%d\n", reloc, rel->r_offset, rel_type); |
+ |
+ // Apply the relocation. |
+ ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc); |
+ switch (rel_type) { |
+#ifdef __arm__ |
+ case R_ARM_JUMP_SLOT: |
+ RLOG(" R_ARM_JUMP_SLOT target=%p addr=%p\n", target, sym_addr); |
+ *target = sym_addr; |
+ break; |
+ |
+ case R_ARM_GLOB_DAT: |
+ RLOG(" R_ARM_GLOB_DAT target=%p addr=%p\n", target, sym_addr); |
+ *target = sym_addr; |
+ break; |
+ |
+ case R_ARM_ABS32: |
+ RLOG(" R_ARM_ABS32 target=%p (%p) addr=%p\n", |
+ target, |
+ *target, |
+ sym_addr); |
+ *target += sym_addr; |
+ break; |
+ |
+ case R_ARM_REL32: |
+ RLOG(" R_ARM_REL32 target=%p (%p) addr=%p offset=%p\n", |
+ target, |
+ *target, |
+ sym_addr, |
+ rel->r_offset); |
+ *target += sym_addr - rel->r_offset; |
+ break; |
+ |
+ case R_ARM_RELATIVE: |
+ RLOG(" R_ARM_RELATIVE target=%p (%p) bias=%p\n", |
+ target, |
+ *target, |
+ load_bias_); |
+ if (__builtin_expect(rel_symbol, 0)) { |
+ *error = "Invalid relative relocation with symbol"; |
+ return false; |
+ } |
+ *target += load_bias_; |
+ break; |
+ |
+ case R_ARM_COPY: |
+ // NOTE: These relocations are forbidden in shared libraries. |
+ // The Android linker has special code to deal with this, which |
+ // is not needed here. |
+ RLOG(" R_ARM_COPY\n"); |
+ *error = "Invalid R_ARM_COPY relocation in shared library"; |
+ return false; |
+#endif // __arm__ |
+ |
+#ifdef __i386__ |
+ case R_386_JMP_SLOT: |
+ *target = sym_addr; |
+ break; |
+ |
+ case R_386_GLOB_DAT: |
+ *target = sym_addr; |
+ break; |
+ |
+ case R_386_RELATIVE: |
+ if (rel_symbol) { |
+ *error = "Invalid relative relocation with symbol"; |
+ return false; |
+ } |
+ *target += load_bias_; |
+ break; |
+ |
+ case R_386_32: |
+ *target += sym_addr; |
+ break; |
+ |
+ case R_386_PC32: |
+ *target += (sym_addr - reloc); |
+ break; |
+#endif // __i386__ |
+ |
+#ifdef __mips__ |
+ case R_MIPS_REL32: |
+ if (resolved) |
+ *target += sym_addr; |
+ else |
+ *target += load_bias_; |
+ break; |
+#endif // __mips__ |
+ |
+ default: |
+ error->Format("Invalid relocation type (%d)", rel_type); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool ElfRelocations::ResolveSymbol(ELF::Word rel_type, |
+ ELF::Word rel_symbol, |
+ const ElfSymbols* symbols, |
+ SymbolResolver* resolver, |
+ ELF::Addr reloc, |
+ ELF::Addr* sym_addr, |
+ Error* error) { |
+ const char* sym_name = symbols->LookupNameById(rel_symbol); |
+ RLOG(" symbol name='%s'\n", sym_name); |
+ void* address = resolver->Lookup(sym_name); |
+ |
+ if (address) { |
+ // The symbol was found, so compute its address. |
+ RLOG("%s: symbol %s resolved to %p\n", __FUNCTION__, sym_name, address); |
+ *sym_addr = reinterpret_cast<ELF::Addr>(address); |
+ return true; |
+ } |
+ |
+ // The symbol was not found. Normally this is an error except |
+ // if this is a weak reference. |
+ if (!symbols->IsWeakById(rel_symbol)) { |
+ error->Format("Could not find symbol '%s'", sym_name); |
+ return false; |
+ } |
+ |
+ RLOG("%s: weak reference to unresolved symbol %s\n", __FUNCTION__, sym_name); |
+ |
+ // IHI0044C AAELF 4.5.1.1: |
+ // Libraries are not searched to resolve weak references. |
+ // It is not an error for a weak reference to remain |
+ // unsatisfied. |
+ // |
+ // During linking, the value of an undefined weak reference is: |
+ // - Zero if the relocation type is absolute |
+ // - The address of the place if the relocation is pc-relative |
+ // - The address of nominal base address if the relocation |
+ // type is base-relative. |
+ RelocationType r = GetRelocationType(rel_type); |
+ if (r == RELOCATION_TYPE_ABSOLUTE || r == RELOCATION_TYPE_RELATIVE) { |
+ *sym_addr = 0; |
+ return true; |
+ } |
+ |
+ if (r == RELOCATION_TYPE_PC_RELATIVE) { |
+ *sym_addr = reloc; |
+ return true; |
+ } |
+ |
+ error->Format( |
+ "Invalid weak relocation type (%d) for unknown symbol '%s'", |
+ r, |
+ sym_name); |
+ return false; |
+} |
+ |
+bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel, |
+ size_t rel_count, |
+ const ElfSymbols* symbols, |
+ SymbolResolver* resolver, |
+ Error* error) { |
RLOG("%s: rel=%p rel_count=%d\n", __FUNCTION__, rel, rel_count); |
if (!rel) |
return true; |
for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) { |
- unsigned rel_type = ELF_R_TYPE(rel->r_info); |
- unsigned rel_symbol = ELF_R_SYM(rel->r_info); |
+ const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); |
+ const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); |
ELF::Addr sym_addr = 0; |
ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); |
@@ -263,147 +574,68 @@ bool ElfRelocations::ApplyRelocs(const ELF::Rel* rel, |
if (rel_type == 0) |
continue; |
- bool CRAZY_UNUSED resolved = false; |
+ bool resolved = false; |
// If this is a symbolic relocation, compute the symbol's address. |
if (__builtin_expect(rel_symbol != 0, 0)) { |
- const char* sym_name = symbols->LookupNameById(rel_symbol); |
- RLOG(" symbol name='%s'\n", sym_name); |
- void* address = resolver->Lookup(sym_name); |
- if (address) { |
- // The symbol was found, so compute its address. |
- RLOG("%s: symbol %s resolved to %p\n", __FUNCTION__, sym_name, address); |
- resolved = true; |
- sym_addr = reinterpret_cast<ELF::Addr>(address); |
- } else { |
- // The symbol was not found. Normally this is an error except |
- // if this is a weak reference. |
- if (!symbols->IsWeakById(rel_symbol)) { |
- error->Format("Could not find symbol '%s'", sym_name); |
- return false; |
- } |
- |
- resolved = true; |
- RLOG("%s: weak reference to unresolved symbol %s\n", |
- __FUNCTION__, |
- sym_name); |
- |
- // IHI0044C AAELF 4.5.1.1: |
- // Libraries are not searched to resolve weak references. |
- // It is not an error for a weak reference to remain |
- // unsatisfied. |
- // |
- // During linking, the value of an undefined weak reference is: |
- // - Zero if the relocation type is absolute |
- // - The address of the place if the relocation is pc-relative |
- // - The address of nominal base address if the relocation |
- // type is base-relative. |
- RelocationType r = GetRelocationType(rel_type); |
- if (r == RELOCATION_TYPE_ABSOLUTE || r == RELOCATION_TYPE_RELATIVE) |
- sym_addr = 0; |
- else if (r == RELOCATION_TYPE_PC_RELATIVE) |
- sym_addr = reloc; |
- else { |
- error->Format( |
- "Invalid weak relocation type (%d) for unknown symbol '%s'", |
- r, |
- sym_name); |
- return false; |
- } |
- } |
+ resolved = ResolveSymbol(rel_type, |
+ rel_symbol, |
+ symbols, |
+ resolver, |
+ reloc, |
+ &sym_addr, |
+ error); |
} |
- // Apply the relocation. |
- ELF::Addr* target = reinterpret_cast<ELF::Addr*>(reloc); |
- switch (rel_type) { |
-#ifdef __arm__ |
- case R_ARM_JUMP_SLOT: |
- RLOG(" R_ARM_JUMP_SLOT target=%p addr=%p\n", target, sym_addr); |
- *target = sym_addr; |
- break; |
- |
- case R_ARM_GLOB_DAT: |
- RLOG(" R_ARM_GLOB_DAT target=%p addr=%p\n", target, sym_addr); |
- *target = sym_addr; |
- break; |
- |
- case R_ARM_ABS32: |
- RLOG(" R_ARM_ABS32 target=%p (%p) addr=%p\n", |
- target, |
- *target, |
- sym_addr); |
- *target += sym_addr; |
- break; |
- |
- case R_ARM_REL32: |
- RLOG(" R_ARM_REL32 target=%p (%p) addr=%p offset=%p\n", |
- target, |
- *target, |
- sym_addr, |
- rel->r_offset); |
- *target += sym_addr - rel->r_offset; |
- break; |
- |
- case R_ARM_RELATIVE: |
- RLOG(" R_ARM_RELATIVE target=%p (%p) bias=%p\n", |
- target, |
- *target, |
- load_bias_); |
- if (__builtin_expect(rel_symbol, 0)) { |
- *error = "Invalid relative relocation with symbol"; |
- return false; |
- } |
- *target += load_bias_; |
- break; |
+ if (!ApplyRelReloc(rel, sym_addr, resolved, error)) |
+ return false; |
+ } |
- case R_ARM_COPY: |
- // NOTE: These relocations are forbidden in shared libraries. |
- // The Android linker has special code to deal with this, which |
- // is not needed here. |
- RLOG(" R_ARM_COPY\n"); |
- *error = "Invalid R_ARM_COPY relocation in shared library"; |
- return false; |
-#endif // __arm__ |
+ return true; |
+} |
-#ifdef __i386__ |
- case R_386_JMP_SLOT: |
- *target = sym_addr; |
- break; |
+bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela, |
+ size_t rela_count, |
+ const ElfSymbols* symbols, |
+ SymbolResolver* resolver, |
+ Error* error) { |
+ RLOG("%s: rela=%p rela_count=%d\n", __FUNCTION__, rela, rela_count); |
- case R_386_GLOB_DAT: |
- *target = sym_addr; |
- break; |
+ if (!rela) |
+ return true; |
- case R_386_RELATIVE: |
- if (rel_symbol) { |
- *error = "Invalid relative relocation with symbol"; |
- return false; |
- } |
- *target += load_bias_; |
- break; |
+ for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) { |
+ const ELF::Word rel_type = ELF_R_TYPE(rela->r_info); |
+ const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info); |
- case R_386_32: |
- *target += sym_addr; |
- break; |
+ ELF::Addr sym_addr = 0; |
+ ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); |
+ RLOG(" %d/%d reloc=%p offset=%p type=%d symbol=%d\n", |
+ rel_n + 1, |
+ rela_count, |
+ reloc, |
+ rela->r_offset, |
+ rel_type, |
+ rel_symbol); |
- case R_386_PC32: |
- *target += (sym_addr - reloc); |
- break; |
-#endif // __i386__ |
+ if (rel_type == 0) |
Anton
2014/06/11 15:31:54
Is there is no symbolic name for this type?
|
+ continue; |
-#ifdef __mips__ |
- case R_MIPS_REL32: |
- if (resolved) |
- *target += sym_addr; |
- else |
- *target += load_bias_; |
- break; |
-#endif // __mips__ |
+ bool resolved = false; |
- default: |
- error->Format("Invalid relocation type (%d)", rel_type); |
- return false; |
+ // If this is a symbolic relocation, compute the symbol's address. |
+ if (__builtin_expect(rel_symbol != 0, 0)) { |
+ resolved = ResolveSymbol(rel_type, |
+ rel_symbol, |
+ symbols, |
+ resolver, |
+ reloc, |
+ &sym_addr, |
+ error); |
} |
+ |
+ if (!ApplyRelaReloc(rela, sym_addr, resolved, error)) |
+ return false; |
} |
return true; |
@@ -457,27 +689,58 @@ bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols, |
} |
#endif // __mips__ |
-void ElfRelocations::CopyAndRelocate(size_t src_addr, |
- size_t dst_addr, |
- size_t map_addr, |
- size_t size) { |
- // First, a straight copy. |
- ::memcpy(reinterpret_cast<void*>(dst_addr), |
- reinterpret_cast<void*>(src_addr), |
- size); |
+void ElfRelocations::AdjustRelocation(ELF::Word rel_type, |
+ ELF::Addr src_reloc, |
+ size_t dst_delta, |
+ size_t map_delta) { |
+ ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(src_reloc + dst_delta); |
+ |
+ switch (rel_type) { |
+#ifdef __arm__ |
+ case R_ARM_RELATIVE: |
+ *dst_ptr += map_delta; |
+ break; |
+#endif // __arm__ |
+#ifdef __aarch64__ |
+ case R_AARCH64_RELATIVE: |
+ *dst_ptr += map_delta; |
+ break; |
+#endif // __aarch64__ |
+ |
+#ifdef __i386__ |
+ case R_386_RELATIVE: |
+ *dst_ptr += map_delta; |
+ break; |
+#endif |
Anton
2014/06/11 15:31:54
for consistency add // __i386__
also L721.
|
+ |
+#ifdef __mips__ |
+ case R_MIPS_REL32: |
+ *dst_ptr += map_delta; |
+ break; |
+#endif |
+ default: |
+ ; |
+ } |
+} |
+ |
+void ElfRelocations::RelocateRela(size_t src_addr, |
+ size_t dst_addr, |
+ size_t map_addr, |
Anton
2014/06/11 15:31:54
If these things are addresses why is their type si
|
+ size_t size) { |
// Add this value to each source address to get the corresponding |
// destination address. |
- size_t dst_delta = dst_addr - src_addr; |
- size_t map_delta = map_addr - src_addr; |
+ const size_t dst_delta = dst_addr - src_addr; |
+ const size_t map_delta = map_addr - src_addr; |
// Ignore PLT relocations, which all target symbols (ignored here). |
- const ELF::Rel* rel = relocations_; |
- const ELF::Rel* rel_limit = rel + relocations_count_; |
+ const ELF::Rela* rel = reinterpret_cast<ELF::Rela*>(relocations_); |
+ const size_t relocations_count = relocations_size_ / sizeof(ELF::Rela); |
+ const ELF::Rela* rel_limit = rel + relocations_count; |
for (; rel < rel_limit; ++rel) { |
- unsigned rel_type = ELF_R_TYPE(rel->r_info); |
- unsigned rel_symbol = ELF_R_SYM(rel->r_info); |
+ const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); |
+ const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); |
ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); |
if (rel_type == 0 || rel_symbol != 0) { |
@@ -490,32 +753,65 @@ void ElfRelocations::CopyAndRelocate(size_t src_addr, |
continue; |
} |
- ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(src_reloc + dst_delta); |
+ AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta); |
+ } |
+} |
- switch (rel_type) { |
-#ifdef __arm__ |
- case R_ARM_RELATIVE: |
- *dst_ptr += map_delta; |
- break; |
-#endif // __arm__ |
+void ElfRelocations::RelocateRel(size_t src_addr, |
+ size_t dst_addr, |
+ size_t map_addr, |
+ size_t size) { |
+ // Add this value to each source address to get the corresponding |
+ // destination address. |
+ const size_t dst_delta = dst_addr - src_addr; |
+ const size_t map_delta = map_addr - src_addr; |
-#ifdef __i386__ |
- case R_386_RELATIVE: |
- *dst_ptr += map_delta; |
- break; |
-#endif |
+ // Ignore PLT relocations, which all target symbols (ignored here). |
+ const ELF::Rel* rel = reinterpret_cast<ELF::Rel*>(relocations_); |
+ const size_t relocations_count = relocations_size_ / sizeof(ELF::Rel); |
+ const ELF::Rel* rel_limit = rel + relocations_count; |
-#ifdef __mips__ |
- case R_MIPS_REL32: |
- *dst_ptr += map_delta; |
- break; |
-#endif |
- default: |
- ; |
+ for (; rel < rel_limit; ++rel) { |
+ const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); |
+ const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); |
+ ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); |
+ |
+ if (rel_type == 0 || rel_symbol != 0) { |
+ // Ignore empty and symbolic relocations |
+ continue; |
} |
+ |
+ if (src_reloc < src_addr || src_reloc >= src_addr + size) { |
+ // Ignore entries that don't relocate addresses inside the source section. |
+ continue; |
+ } |
+ |
+ AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta); |
} |
+} |
+ |
+void ElfRelocations::CopyAndRelocate(size_t src_addr, |
+ size_t dst_addr, |
+ size_t map_addr, |
+ size_t size) { |
+ // First, a straight copy. |
+ ::memcpy(reinterpret_cast<void*>(dst_addr), |
+ reinterpret_cast<void*>(src_addr), |
+ size); |
+ |
+ // Relocate relocations. |
+ if (relocations_type_ == DT_REL) |
+ RelocateRel(src_addr, dst_addr, map_addr, size); |
+ |
+ else if (relocations_type_ == DT_RELA) |
+ RelocateRela(src_addr, dst_addr, map_addr, size); |
#ifdef __mips__ |
+ // Add this value to each source address to get the corresponding |
+ // destination address. |
+ const size_t dst_delta = dst_addr - src_addr; |
+ const size_t map_delta = map_addr - src_addr; |
+ |
// Only relocate local GOT entries. |
ELF::Addr* got = plt_got_; |
if (got) { |
@@ -528,8 +824,6 @@ void ElfRelocations::CopyAndRelocate(size_t src_addr, |
} |
} |
#endif |
- |
- // Done |
} |
} // namespace crazy |