|
@@ -26,6 +26,9 @@ bool perform_relative_relocations(FlatPtr base_address)
|
|
|
FlatPtr relocation_section_addr = 0;
|
|
|
size_t relocation_table_size = 0;
|
|
|
size_t relocation_count = 0;
|
|
|
+ size_t relocation_entry_size = 0;
|
|
|
+ FlatPtr relr_relocation_section_addr = 0;
|
|
|
+ size_t relr_relocation_table_size = 0;
|
|
|
bool use_addend = false;
|
|
|
auto* dyns = reinterpret_cast<const ElfW(Dyn)*>(dynamic_section_addr);
|
|
|
for (unsigned i = 0;; ++i) {
|
|
@@ -40,11 +43,19 @@ bool perform_relative_relocations(FlatPtr base_address)
|
|
|
relocation_count = dyn.d_un.d_val;
|
|
|
else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
|
|
|
relocation_table_size = dyn.d_un.d_val;
|
|
|
+ else if (dyn.d_tag == DT_RELENT || dyn.d_tag == DT_RELAENT)
|
|
|
+ relocation_entry_size = dyn.d_un.d_val;
|
|
|
+ else if (dyn.d_tag == DT_RELR)
|
|
|
+ relr_relocation_section_addr = base_address + dyn.d_un.d_ptr;
|
|
|
+ else if (dyn.d_tag == DT_RELRSZ)
|
|
|
+ relr_relocation_table_size = dyn.d_un.d_val;
|
|
|
+ else if (dyn.d_tag == DT_RELRENT)
|
|
|
+ VERIFY(dyn.d_un.d_val == sizeof(FlatPtr));
|
|
|
}
|
|
|
- if (!relocation_section_addr || !relocation_table_size || !relocation_count)
|
|
|
+
|
|
|
+ if ((!relocation_section_addr || !relocation_table_size || !relocation_count) && (!relr_relocation_section_addr || !relr_relocation_table_size))
|
|
|
return false;
|
|
|
|
|
|
- auto relocation_entry_size = relocation_table_size / relocation_count;
|
|
|
for (unsigned i = 0; i < relocation_count; ++i) {
|
|
|
size_t offset_in_section = i * relocation_entry_size;
|
|
|
auto* relocation = (ElfW(Rela)*)(relocation_section_addr + offset_in_section);
|
|
@@ -64,6 +75,30 @@ bool perform_relative_relocations(FlatPtr base_address)
|
|
|
__builtin_memcpy(patch_address, &relocated_address, sizeof(relocated_address));
|
|
|
}
|
|
|
|
|
|
+ auto patch_relr = [base_address](FlatPtr* patch_ptr) {
|
|
|
+ FlatPtr relocated_address;
|
|
|
+ __builtin_memcpy(&relocated_address, patch_ptr, sizeof(FlatPtr));
|
|
|
+ relocated_address += base_address;
|
|
|
+ __builtin_memcpy(patch_ptr, &relocated_address, sizeof(FlatPtr));
|
|
|
+ };
|
|
|
+
|
|
|
+ auto* entries = reinterpret_cast<ElfW(Relr)*>(relr_relocation_section_addr);
|
|
|
+ FlatPtr* patch_ptr = nullptr;
|
|
|
+
|
|
|
+ for (unsigned i = 0; i < relr_relocation_table_size / sizeof(FlatPtr); ++i) {
|
|
|
+ if ((entries[i] & 1u) == 0) {
|
|
|
+ patch_ptr = reinterpret_cast<FlatPtr*>(base_address + entries[i]);
|
|
|
+ patch_relr(patch_ptr);
|
|
|
+ ++patch_ptr;
|
|
|
+ } else {
|
|
|
+ unsigned j = 0;
|
|
|
+ for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j)
|
|
|
+ if (bitmap & 1u)
|
|
|
+ patch_relr(patch_ptr + j);
|
|
|
+
|
|
|
+ patch_ptr += 8 * sizeof(FlatPtr) - 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
}
|