ELFLoader.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "ELFLoader.h"
  2. #include <AK/kstdio.h>
  3. //#define ELFLOADER_DEBUG
  4. //#define SUPPORT_RELOCATIONS
  5. ELFLoader::ELFLoader(const byte* buffer)
  6. : m_image(buffer)
  7. {
  8. }
  9. ELFLoader::~ELFLoader()
  10. {
  11. }
  12. bool ELFLoader::load()
  13. {
  14. #ifdef ELFLOADER_DEBUG
  15. m_image.dump();
  16. #endif
  17. if (!m_image.is_valid())
  18. return false;
  19. if (!layout())
  20. return false;
  21. #ifdef SUPPORT_RELOCATIONS
  22. if (!perform_relocations())
  23. return false;
  24. #endif
  25. return true;
  26. }
  27. bool ELFLoader::layout()
  28. {
  29. #ifdef ELFLOADER_DEBUG
  30. kprintf("ELFLoader: Layout\n");
  31. #endif
  32. bool failed = false;
  33. m_image.for_each_program_header([&] (const ELFImage::ProgramHeader& program_header) {
  34. if (program_header.type() != PT_LOAD)
  35. return;
  36. #ifdef ELFLOADER_DEBUG
  37. kprintf("PH: L%x %u r:%u w:%u\n", program_header.laddr().get(), program_header.size_in_memory(), program_header.is_readable(), program_header.is_writable());
  38. #endif
  39. if (program_header.is_writable()) {
  40. alloc_section_hook(
  41. program_header.laddr(),
  42. program_header.size_in_memory(),
  43. program_header.alignment(),
  44. program_header.is_readable(),
  45. program_header.is_writable(),
  46. String::format("elf-alloc-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "")
  47. );
  48. memcpy(program_header.laddr().as_ptr(), program_header.raw_data(), program_header.size_in_image());
  49. } else {
  50. map_section_hook(
  51. program_header.laddr(),
  52. program_header.size_in_memory(),
  53. program_header.alignment(),
  54. program_header.offset(),
  55. program_header.is_readable(),
  56. program_header.is_writable(),
  57. String::format("elf-map-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "")
  58. );
  59. }
  60. });
  61. return !failed;
  62. }
  63. #ifdef SUPPORT_RELOCATIONS
  64. void* ELFLoader::lookup(const ELFImage::Symbol& symbol)
  65. {
  66. if (symbol.section().is_undefined())
  67. return symbol_ptr(symbol.name());
  68. return area_for_section(symbol.section()) + symbol.value();
  69. }
  70. #endif
  71. #ifdef SUPPORT_RELOCATIONS
  72. char* ELFLoader::area_for_section(const ELFImage::Section& section)
  73. {
  74. return area_for_section_name(section.name());
  75. }
  76. char* ELFLoader::area_for_section_name(const char* name)
  77. {
  78. if (auto it = m_sections.find(name); it != m_sections.end())
  79. return (*it).value;
  80. ASSERT_NOT_REACHED();
  81. return nullptr;
  82. }
  83. #endif
  84. #ifdef SUPPORT_RELOCATIONS
  85. bool ELFLoader::perform_relocations()
  86. {
  87. #ifdef ELFLOADER_DEBUG
  88. kprintf("ELFLoader: Performing relocations\n");
  89. #endif
  90. bool failed = false;
  91. m_image.for_each_section_of_type(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) -> bool {
  92. auto& relocations = section.relocations();
  93. if (relocations.is_undefined())
  94. return true;
  95. relocations.for_each_relocation([this, section, &failed] (const ELFImage::Relocation& relocation) {
  96. auto symbol = relocation.symbol();
  97. auto& patch_ptr = *reinterpret_cast<ptrdiff_t*>(area_for_section(section) + relocation.offset());
  98. switch (relocation.type()) {
  99. case R_386_PC32: {
  100. char* target_ptr = (char*)lookup(symbol);
  101. if (!target_ptr) {
  102. kprintf("ELFLoader: unresolved symbol '%s'\n", symbol.name());
  103. failed = true;
  104. return false;
  105. }
  106. ptrdiff_t relative_offset = (char*)target_ptr - ((char*)&patch_ptr + 4);
  107. #ifdef ELFLOADER_DEBUG
  108. kprintf("ELFLoader: Relocate PC32: offset=%x, symbol=%u(%s) value=%x target=%p, offset=%d\n",
  109. relocation.offset(),
  110. symbol.index(),
  111. symbol.name(),
  112. symbol.value(),
  113. target_ptr,
  114. relative_offset
  115. );
  116. #endif
  117. patch_ptr = relative_offset;
  118. break;
  119. }
  120. case R_386_32: {
  121. #ifdef ELFLOADER_DEBUG
  122. kprintf("ELFLoader: Relocate Abs32: symbol=%u(%s), value=%x, section=%s\n",
  123. symbol.index(),
  124. symbol.name(),
  125. symbol.value(),
  126. symbol.section().name()
  127. );
  128. #endif
  129. char* target_ptr = area_for_section(symbol.section()) + symbol.value();
  130. patch_ptr += (ptrdiff_t)target_ptr;
  131. break;
  132. }
  133. default:
  134. ASSERT_NOT_REACHED();
  135. break;
  136. }
  137. return true;
  138. });
  139. return !failed;
  140. });
  141. return !failed;
  142. }
  143. #endif
  144. char* ELFLoader::symbol_ptr(const char* name)
  145. {
  146. char* found_ptr = nullptr;
  147. m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) {
  148. if (symbol.type() != STT_FUNC)
  149. return true;
  150. if (strcmp(symbol.name(), name))
  151. return true;
  152. if (m_image.is_executable())
  153. found_ptr = (char*)symbol.value();
  154. #ifdef SUPPORT_RELOCATIONS
  155. else if (m_image.is_relocatable())
  156. found_ptr = area_for_section(symbol.section()) + symbol.value();
  157. #endif
  158. else
  159. ASSERT_NOT_REACHED();
  160. return false;
  161. });
  162. return found_ptr;
  163. }