Relocation.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /*
  2. * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibC/elf.h>
  7. #include <LibELF/Relocation.h>
  8. namespace ELF {
  9. bool perform_relative_relocations(FlatPtr base_address)
  10. {
  11. ElfW(Ehdr)* header = (ElfW(Ehdr)*)(base_address);
  12. ElfW(Phdr)* pheader = (ElfW(Phdr)*)(base_address + header->e_phoff);
  13. FlatPtr dynamic_section_addr = 0;
  14. for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) {
  15. if (pheader->p_type != PT_DYNAMIC)
  16. continue;
  17. dynamic_section_addr = pheader->p_vaddr + base_address;
  18. }
  19. if (!dynamic_section_addr)
  20. return false;
  21. FlatPtr relocation_section_addr = 0;
  22. size_t relocation_table_size = 0;
  23. size_t relocation_count = 0;
  24. bool use_addend = false;
  25. auto* dyns = reinterpret_cast<const ElfW(Dyn)*>(dynamic_section_addr);
  26. for (unsigned i = 0;; ++i) {
  27. auto& dyn = dyns[i];
  28. if (dyn.d_tag == DT_NULL)
  29. break;
  30. if (dyn.d_tag == DT_RELA)
  31. use_addend = true;
  32. if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELA)
  33. relocation_section_addr = base_address + dyn.d_un.d_ptr;
  34. else if (dyn.d_tag == DT_RELCOUNT || dyn.d_tag == DT_RELACOUNT)
  35. relocation_count = dyn.d_un.d_val;
  36. else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
  37. relocation_table_size = dyn.d_un.d_val;
  38. }
  39. if (!relocation_section_addr || !relocation_table_size || !relocation_count)
  40. return false;
  41. auto relocation_entry_size = relocation_table_size / relocation_count;
  42. for (unsigned i = 0; i < relocation_count; ++i) {
  43. size_t offset_in_section = i * relocation_entry_size;
  44. auto* relocation = (ElfW(Rela)*)(relocation_section_addr + offset_in_section);
  45. #if ARCH(I386)
  46. VERIFY(ELF32_R_TYPE(relocation->r_info) == R_386_RELATIVE);
  47. #else
  48. VERIFY(ELF64_R_TYPE(relocation->r_info) == R_X86_64_RELATIVE);
  49. #endif
  50. auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset);
  51. FlatPtr relocated_address;
  52. if (use_addend) {
  53. relocated_address = base_address + relocation->r_addend;
  54. } else {
  55. __builtin_memcpy(&relocated_address, patch_address, sizeof(relocated_address));
  56. relocated_address += base_address;
  57. }
  58. __builtin_memcpy(patch_address, &relocated_address, sizeof(relocated_address));
  59. }
  60. return true;
  61. }
  62. }