Relocation.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibELF/Arch/GenericDynamicRelocationType.h>
  7. #include <LibELF/ELFABI.h>
  8. #include <LibELF/Relocation.h>
  9. namespace ELF {
  10. bool perform_relative_relocations(FlatPtr base_address)
  11. {
  12. Elf_Ehdr* header = (Elf_Ehdr*)(base_address);
  13. Elf_Phdr* pheader = (Elf_Phdr*)(base_address + header->e_phoff);
  14. FlatPtr dynamic_section_addr = 0;
  15. for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) {
  16. if (pheader->p_type != PT_DYNAMIC)
  17. continue;
  18. dynamic_section_addr = pheader->p_vaddr + base_address;
  19. }
  20. if (!dynamic_section_addr)
  21. return false;
  22. FlatPtr relocation_section_addr = 0;
  23. size_t relocation_table_size = 0;
  24. size_t relocation_count = 0;
  25. size_t relocation_entry_size = 0;
  26. FlatPtr relr_relocation_section_addr = 0;
  27. size_t relr_relocation_table_size = 0;
  28. bool use_addend = false;
  29. auto* dyns = reinterpret_cast<Elf_Dyn const*>(dynamic_section_addr);
  30. for (unsigned i = 0;; ++i) {
  31. auto& dyn = dyns[i];
  32. if (dyn.d_tag == DT_NULL)
  33. break;
  34. if (dyn.d_tag == DT_RELA)
  35. use_addend = true;
  36. if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELA)
  37. relocation_section_addr = base_address + dyn.d_un.d_ptr;
  38. else if (dyn.d_tag == DT_RELCOUNT || dyn.d_tag == DT_RELACOUNT)
  39. relocation_count = dyn.d_un.d_val;
  40. else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
  41. relocation_table_size = dyn.d_un.d_val;
  42. else if (dyn.d_tag == DT_RELENT || dyn.d_tag == DT_RELAENT)
  43. relocation_entry_size = dyn.d_un.d_val;
  44. else if (dyn.d_tag == DT_RELR)
  45. relr_relocation_section_addr = base_address + dyn.d_un.d_ptr;
  46. else if (dyn.d_tag == DT_RELRSZ)
  47. relr_relocation_table_size = dyn.d_un.d_val;
  48. else if (dyn.d_tag == DT_RELRENT)
  49. VERIFY(dyn.d_un.d_val == sizeof(FlatPtr));
  50. }
  51. if ((!relocation_section_addr || !relocation_table_size || !relocation_count) && (!relr_relocation_section_addr || !relr_relocation_table_size))
  52. return false;
  53. for (unsigned i = 0; i < relocation_count; ++i) {
  54. size_t offset_in_section = i * relocation_entry_size;
  55. auto* relocation = (Elf_Rela*)(relocation_section_addr + offset_in_section);
  56. VERIFY(static_cast<GenericDynamicRelocationType>(ELF64_R_TYPE(relocation->r_info)) == GenericDynamicRelocationType::RELATIVE);
  57. auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset);
  58. FlatPtr relocated_address;
  59. if (use_addend) {
  60. relocated_address = base_address + relocation->r_addend;
  61. } else {
  62. __builtin_memcpy(&relocated_address, patch_address, sizeof(relocated_address));
  63. relocated_address += base_address;
  64. }
  65. __builtin_memcpy(patch_address, &relocated_address, sizeof(relocated_address));
  66. }
  67. auto patch_relr = [base_address](FlatPtr* patch_ptr) {
  68. FlatPtr relocated_address;
  69. __builtin_memcpy(&relocated_address, patch_ptr, sizeof(FlatPtr));
  70. relocated_address += base_address;
  71. __builtin_memcpy(patch_ptr, &relocated_address, sizeof(FlatPtr));
  72. };
  73. auto* entries = reinterpret_cast<Elf_Relr*>(relr_relocation_section_addr);
  74. FlatPtr* patch_ptr = nullptr;
  75. for (unsigned i = 0; i < relr_relocation_table_size / sizeof(FlatPtr); ++i) {
  76. if ((entries[i] & 1u) == 0) {
  77. patch_ptr = reinterpret_cast<FlatPtr*>(base_address + entries[i]);
  78. patch_relr(patch_ptr);
  79. ++patch_ptr;
  80. } else {
  81. unsigned j = 0;
  82. for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j)
  83. if (bitmap & 1u)
  84. patch_relr(patch_ptr + j);
  85. patch_ptr += 8 * sizeof(FlatPtr) - 1;
  86. }
  87. }
  88. return true;
  89. }
  90. }