ELFDynamicObject.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #pragma once
  2. #include <LibELF/exec_elf.h>
  3. #include <Kernel/VM/VirtualAddress.h>
  4. class ELFDynamicObject {
  5. public:
  6. explicit ELFDynamicObject(VirtualAddress base_address, u32 dynamic_offset);
  7. ~ELFDynamicObject();
  8. void dump() const;
  9. class DynamicEntry;
  10. class Section;
  11. class RelocationSection;
  12. class Symbol;
  13. class Relocation;
  14. class HashSection;
  15. class DynamicEntry {
  16. public:
  17. DynamicEntry(const Elf32_Dyn& dyn)
  18. : m_dyn(dyn)
  19. {
  20. }
  21. ~DynamicEntry() {}
  22. Elf32_Sword tag() const { return m_dyn.d_tag; }
  23. Elf32_Addr ptr() const { return m_dyn.d_un.d_ptr; }
  24. Elf32_Word val() const { return m_dyn.d_un.d_val; }
  25. private:
  26. const Elf32_Dyn& m_dyn;
  27. };
  28. class Symbol {
  29. public:
  30. Symbol(const ELFDynamicObject& dynamic, unsigned index, const Elf32_Sym& sym)
  31. : m_dynamic(dynamic)
  32. , m_sym(sym)
  33. , m_index(index)
  34. {
  35. }
  36. ~Symbol() {}
  37. const char* name() const { return m_dynamic.symbol_string_table_string(m_sym.st_name); }
  38. unsigned section_index() const { return m_sym.st_shndx; }
  39. unsigned value() const { return m_sym.st_value; }
  40. unsigned size() const { return m_sym.st_size; }
  41. unsigned index() const { return m_index; }
  42. unsigned type() const { return ELF32_ST_TYPE(m_sym.st_info); }
  43. unsigned bind() const { return ELF32_ST_BIND(m_sym.st_info); }
  44. bool is_undefined() const { return this == &m_dynamic.the_undefined_symbol(); }
  45. VirtualAddress address() const { return m_dynamic.base_address().offset(value()); }
  46. private:
  47. const ELFDynamicObject& m_dynamic;
  48. const Elf32_Sym& m_sym;
  49. const unsigned m_index;
  50. };
  51. class Section {
  52. public:
  53. Section(const ELFDynamicObject& dynamic, unsigned section_offset, unsigned section_size_bytes, unsigned entry_size, const char* name)
  54. : m_dynamic(dynamic)
  55. , m_section_offset(section_offset)
  56. , m_section_size_bytes(section_size_bytes)
  57. , m_entry_size(entry_size)
  58. , m_name(name)
  59. {
  60. }
  61. ~Section() {}
  62. const char* name() const { return m_name; }
  63. unsigned offset() const { return m_section_offset; }
  64. unsigned size() const { return m_section_size_bytes; }
  65. unsigned entry_size() const { return m_entry_size; }
  66. unsigned entry_count() const { return !entry_size() ? 0 : size() / entry_size(); }
  67. VirtualAddress address() const { return m_dynamic.base_address().offset(m_section_offset); }
  68. protected:
  69. friend class RelocationSection;
  70. friend class HashSection;
  71. const ELFDynamicObject& m_dynamic;
  72. unsigned m_section_offset;
  73. unsigned m_section_size_bytes;
  74. unsigned m_entry_size;
  75. const char* m_name { nullptr };
  76. };
  77. class RelocationSection : public Section {
  78. public:
  79. RelocationSection(const Section& section)
  80. : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name)
  81. {
  82. }
  83. unsigned relocation_count() const { return entry_count(); }
  84. const Relocation relocation(unsigned index) const;
  85. const Relocation relocation_at_offset(unsigned offset) const;
  86. template<typename F>
  87. void for_each_relocation(F) const;
  88. };
  89. class Relocation {
  90. public:
  91. Relocation(const ELFDynamicObject& dynamic, const Elf32_Rel& rel, unsigned offset_in_section)
  92. : m_dynamic(dynamic)
  93. , m_rel(rel)
  94. , m_offset_in_section(offset_in_section)
  95. {
  96. }
  97. ~Relocation() {}
  98. unsigned offset_in_section() const { return m_offset_in_section; }
  99. unsigned offset() const { return m_rel.r_offset; }
  100. unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); }
  101. unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); }
  102. const Symbol symbol() const { return m_dynamic.symbol(symbol_index()); }
  103. VirtualAddress address() const { return m_dynamic.base_address().offset(offset()); }
  104. private:
  105. const ELFDynamicObject& m_dynamic;
  106. const Elf32_Rel& m_rel;
  107. const unsigned m_offset_in_section;
  108. };
  109. enum class HashType {
  110. SYSV,
  111. GNU
  112. };
  113. class HashSection : public Section {
  114. public:
  115. HashSection(const Section& section, HashType hash_type = HashType::SYSV)
  116. : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name)
  117. {
  118. switch (hash_type) {
  119. case HashType::SYSV:
  120. m_hash_function = &HashSection::calculate_elf_hash;
  121. break;
  122. case HashType::GNU:
  123. m_hash_function = &HashSection::calculate_gnu_hash;
  124. break;
  125. default:
  126. ASSERT_NOT_REACHED();
  127. break;
  128. }
  129. }
  130. const Symbol lookup_symbol(const char*) const;
  131. private:
  132. u32 calculate_elf_hash(const char* name) const;
  133. u32 calculate_gnu_hash(const char* name) const;
  134. typedef u32 (HashSection::*HashFunction)(const char*) const;
  135. HashFunction m_hash_function;
  136. };
  137. unsigned symbol_count() const { return m_symbol_count; }
  138. const Symbol symbol(unsigned) const;
  139. const Symbol& the_undefined_symbol() const { return m_the_undefined_symbol; }
  140. const Section init_section() const;
  141. const Section fini_section() const;
  142. const Section init_array_section() const;
  143. const Section fini_array_section() const;
  144. const HashSection hash_section() const;
  145. const RelocationSection relocation_section() const;
  146. const RelocationSection plt_relocation_section() const;
  147. bool should_process_origin() const { return m_dt_flags & DF_ORIGIN; }
  148. bool requires_symbolic_symbol_resolution() const { return m_dt_flags & DF_SYMBOLIC; }
  149. // Text relocations meaning: we need to edit the .text section which is normally mapped PROT_READ
  150. bool has_text_relocations() const { return m_dt_flags & DF_TEXTREL; }
  151. bool must_bind_now() const { return m_dt_flags & DF_BIND_NOW; }
  152. bool has_static_thread_local_storage() const { return m_dt_flags & DF_STATIC_TLS; }
  153. VirtualAddress plt_got_base_address() const { return m_base_address.offset(m_procedure_linkage_table_offset); }
  154. VirtualAddress base_address() const { return m_base_address; }
  155. private:
  156. const char* symbol_string_table_string(Elf32_Word) const;
  157. void parse();
  158. template<typename F>
  159. void for_each_symbol(F) const;
  160. template<typename F>
  161. void for_each_dynamic_entry(F) const;
  162. VirtualAddress m_base_address;
  163. u32 m_dynamic_offset;
  164. Symbol m_the_undefined_symbol { *this, 0, {} };
  165. unsigned m_symbol_count { 0 };
  166. // Begin Section information collected from DT_* entries
  167. uintptr_t m_init_offset { 0 };
  168. uintptr_t m_fini_offset { 0 };
  169. uintptr_t m_init_array_offset { 0 };
  170. size_t m_init_array_size { 0 };
  171. uintptr_t m_fini_array_offset { 0 };
  172. size_t m_fini_array_size { 0 };
  173. uintptr_t m_hash_table_offset { 0 };
  174. uintptr_t m_string_table_offset { 0 };
  175. size_t m_size_of_string_table { 0 };
  176. uintptr_t m_symbol_table_offset { 0 };
  177. size_t m_size_of_symbol_table_entry { 0 };
  178. Elf32_Sword m_procedure_linkage_table_relocation_type { -1 };
  179. uintptr_t m_plt_relocation_offset_location { 0 }; // offset of PLT relocations, at end of relocations
  180. size_t m_size_of_plt_relocation_entry_list { 0 };
  181. uintptr_t m_procedure_linkage_table_offset { 0 };
  182. // NOTE: We'll only ever either RELA or REL entries, not both (thank god)
  183. // NOTE: The x86 ABI will only ever genrerate REL entries.
  184. size_t m_number_of_relocations { 0 };
  185. size_t m_size_of_relocation_entry { 0 };
  186. size_t m_size_of_relocation_table { 0 };
  187. uintptr_t m_relocation_table_offset { 0 };
  188. // DT_FLAGS
  189. Elf32_Word m_dt_flags { 0 };
  190. // End Section information from DT_* entries
  191. };
  192. template<typename F>
  193. inline void ELFDynamicObject::RelocationSection::for_each_relocation(F func) const
  194. {
  195. for (unsigned i = 0; i < relocation_count(); ++i) {
  196. if (func(relocation(i)) == IterationDecision::Break)
  197. break;
  198. }
  199. }
  200. template<typename F>
  201. inline void ELFDynamicObject::for_each_symbol(F func) const
  202. {
  203. for (unsigned i = 0; i < symbol_count(); ++i) {
  204. if (func(symbol(i)) == IterationDecision::Break)
  205. break;
  206. }
  207. }
  208. template<typename F>
  209. inline void ELFDynamicObject::for_each_dynamic_entry(F func) const
  210. {
  211. auto* dyns = reinterpret_cast<const Elf32_Dyn*>(m_base_address.offset(m_dynamic_offset).as_ptr());
  212. for (unsigned i = 0;; ++i) {
  213. auto&& dyn = DynamicEntry(dyns[i]);
  214. if (dyn.tag() == DT_NULL)
  215. break;
  216. if (func(dyn) == IterationDecision::Break)
  217. break;
  218. }
  219. }