ELFLoader.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. allocate_section(program_header.laddr(), program_header.size_in_memory(), program_header.alignment(), program_header.is_readable(), program_header.is_writable());
  41. } else {
  42. map_section(program_header.laddr(), program_header.size_in_memory(), program_header.alignment(), program_header.offset(), program_header.is_readable(), program_header.is_writable());
  43. }
  44. });
  45. m_image.for_each_section_of_type(SHT_PROGBITS, [] (const ELFImage::Section& section) {
  46. #ifdef ELFLOADER_DEBUG
  47. kprintf("ELFLoader: Copying progbits section: %s\n", section.name());
  48. #endif
  49. if (!section.size())
  50. return true;
  51. char* ptr = (char*)section.address();
  52. if (!ptr) {
  53. #ifdef ELFLOADER_DEBUG
  54. kprintf("ELFLoader: ignoring section '%s' with null address\n", section.name());
  55. #endif
  56. return true;
  57. }
  58. // If this section isn't writable, it's already mmapped.
  59. if (section.is_writable())
  60. memcpy(ptr, section.raw_data(), section.size());
  61. #ifdef SUPPORT_RELOCATIONS
  62. m_sections.set(section.name(), move(ptr));
  63. #endif
  64. return true;
  65. });
  66. m_image.for_each_section_of_type(SHT_NOBITS, [&failed] (const ELFImage::Section& section) {
  67. #ifdef ELFLOADER_DEBUG
  68. kprintf("ELFLoader: Copying nobits section: %s\n", section.name());
  69. #endif
  70. if (!section.size())
  71. return true;
  72. char* ptr = (char*)section.address();
  73. if (!ptr) {
  74. kprintf("ELFLoader: failed to allocate section '%s'\n", section.name());
  75. failed = true;
  76. return false;
  77. }
  78. memset(ptr, 0, section.size());
  79. #ifdef SUPPORT_RELOCATIONS
  80. m_sections.set(section.name(), move(ptr));
  81. #endif
  82. return true;
  83. });
  84. return !failed;
  85. }
  86. #ifdef SUPPORT_RELOCATIONS
  87. void* ELFLoader::lookup(const ELFImage::Symbol& symbol)
  88. {
  89. if (symbol.section().is_undefined())
  90. return symbol_ptr(symbol.name());
  91. return area_for_section(symbol.section()) + symbol.value();
  92. }
  93. #endif
  94. #ifdef SUPPORT_RELOCATIONS
  95. char* ELFLoader::area_for_section(const ELFImage::Section& section)
  96. {
  97. return area_for_section_name(section.name());
  98. }
  99. char* ELFLoader::area_for_section_name(const char* name)
  100. {
  101. if (auto it = m_sections.find(name); it != m_sections.end())
  102. return (*it).value;
  103. ASSERT_NOT_REACHED();
  104. return nullptr;
  105. }
  106. #endif
  107. #ifdef SUPPORT_RELOCATIONS
  108. bool ELFLoader::perform_relocations()
  109. {
  110. #ifdef ELFLOADER_DEBUG
  111. kprintf("ELFLoader: Performing relocations\n");
  112. #endif
  113. bool failed = false;
  114. m_image.for_each_section_of_type(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) -> bool {
  115. auto& relocations = section.relocations();
  116. if (relocations.is_undefined())
  117. return true;
  118. relocations.for_each_relocation([this, section, &failed] (const ELFImage::Relocation& relocation) {
  119. auto symbol = relocation.symbol();
  120. auto& patch_ptr = *reinterpret_cast<ptrdiff_t*>(area_for_section(section) + relocation.offset());
  121. switch (relocation.type()) {
  122. case R_386_PC32: {
  123. char* target_ptr = (char*)lookup(symbol);
  124. if (!target_ptr) {
  125. kprintf("ELFLoader: unresolved symbol '%s'\n", symbol.name());
  126. failed = true;
  127. return false;
  128. }
  129. ptrdiff_t relativeOffset = (char*)target_ptr - ((char*)&patch_ptr + 4);
  130. #ifdef ELFLOADER_DEBUG
  131. kprintf("ELFLoader: Relocate PC32: offset=%x, symbol=%u(%s) value=%x target=%p, offset=%d\n",
  132. relocation.offset(),
  133. symbol.index(),
  134. symbol.name(),
  135. symbol.value(),
  136. target_ptr,
  137. relativeOffset
  138. );
  139. #endif
  140. patch_ptr = relativeOffset;
  141. break;
  142. }
  143. case R_386_32: {
  144. #ifdef ELFLOADER_DEBUG
  145. kprintf("ELFLoader: Relocate Abs32: symbol=%u(%s), value=%x, section=%s\n",
  146. symbol.index(),
  147. symbol.name(),
  148. symbol.value(),
  149. symbol.section().name()
  150. );
  151. #endif
  152. char* target_ptr = area_for_section(symbol.section()) + symbol.value();
  153. patch_ptr += (ptrdiff_t)target_ptr;
  154. break;
  155. }
  156. default:
  157. ASSERT_NOT_REACHED();
  158. break;
  159. }
  160. return true;
  161. });
  162. return !failed;
  163. });
  164. return !failed;
  165. }
  166. #endif
  167. char* ELFLoader::symbol_ptr(const char* name)
  168. {
  169. char* found_ptr = nullptr;
  170. m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) {
  171. if (symbol.type() != STT_FUNC)
  172. return true;
  173. if (strcmp(symbol.name(), name))
  174. return true;
  175. if (m_image.is_executable())
  176. found_ptr = (char*)symbol.value();
  177. #ifdef SUPPORT_RELOCATIONS
  178. else if (m_image.is_relocatable())
  179. found_ptr = area_for_section(symbol.section()) + symbol.value();
  180. #endif
  181. else
  182. ASSERT_NOT_REACHED();
  183. return false;
  184. });
  185. return found_ptr;
  186. }
  187. bool ELFLoader::allocate_section(LinearAddress laddr, size_t size, size_t alignment, bool is_readable, bool is_writable)
  188. {
  189. ASSERT(alloc_section_hook);
  190. char namebuf[16];
  191. ksprintf(namebuf, "elf-alloc-%s%s", is_readable ? "r" : "", is_writable ? "w" : "");
  192. return alloc_section_hook(laddr, size, alignment, is_readable, is_writable, namebuf);
  193. }
  194. bool ELFLoader::map_section(LinearAddress laddr, size_t size, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable)
  195. {
  196. ASSERT(alloc_section_hook);
  197. char namebuf[16];
  198. ksprintf(namebuf, "elf-map-%s%s", is_readable ? "r" : "", is_writable ? "w" : "");
  199. return map_section_hook(laddr, size, alignment, offset_in_image, is_readable, is_writable, namebuf);
  200. }