ELFDynamicObject.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * Copyright (c) 2019-2020, Andrew Kaster <andrewdkaster@gmail.com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/String.h>
  27. #include <AK/StringBuilder.h>
  28. #include <LibELF/ELFDynamicObject.h>
  29. #include <LibELF/exec_elf.h>
  30. #include <stdio.h>
  31. static const char* name_for_dtag(Elf32_Sword d_tag);
  32. ELFDynamicObject::ELFDynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_addresss)
  33. : m_base_address(base_address)
  34. , m_dynamic_address(dynamic_section_addresss)
  35. {
  36. parse();
  37. }
  38. ELFDynamicObject::~ELFDynamicObject()
  39. {
  40. }
  41. void ELFDynamicObject::dump() const
  42. {
  43. StringBuilder builder;
  44. builder.append("\nd_tag tag_name value\n");
  45. size_t num_dynamic_sections = 0;
  46. for_each_dynamic_entry([&](const ELFDynamicObject::DynamicEntry& entry) {
  47. String name_field = String::format("(%s)", name_for_dtag(entry.tag()));
  48. builder.appendf("0x%08X %-17s0x%X\n", entry.tag(), name_field.characters(), entry.val());
  49. num_dynamic_sections++;
  50. return IterationDecision::Continue;
  51. });
  52. dbgprintf("Dynamic section at address 0x%x contains %zu entries:\n", m_dynamic_address.as_ptr(), num_dynamic_sections);
  53. dbgprintf(builder.to_string().characters());
  54. }
  55. void ELFDynamicObject::parse()
  56. {
  57. for_each_dynamic_entry([&](const DynamicEntry& entry) {
  58. switch (entry.tag()) {
  59. case DT_INIT:
  60. m_init_offset = entry.ptr();
  61. break;
  62. case DT_FINI:
  63. m_fini_offset = entry.ptr();
  64. break;
  65. case DT_INIT_ARRAY:
  66. m_init_array_offset = entry.ptr();
  67. break;
  68. case DT_INIT_ARRAYSZ:
  69. m_init_array_size = entry.val();
  70. break;
  71. case DT_FINI_ARRAY:
  72. m_fini_array_offset = entry.ptr();
  73. break;
  74. case DT_FINI_ARRAYSZ:
  75. m_fini_array_size = entry.val();
  76. break;
  77. case DT_HASH:
  78. m_hash_table_offset = entry.ptr();
  79. break;
  80. case DT_SYMTAB:
  81. m_symbol_table_offset = entry.ptr();
  82. break;
  83. case DT_STRTAB:
  84. m_string_table_offset = entry.ptr();
  85. break;
  86. case DT_STRSZ:
  87. m_size_of_string_table = entry.val();
  88. break;
  89. case DT_SYMENT:
  90. m_size_of_symbol_table_entry = entry.val();
  91. break;
  92. case DT_PLTGOT:
  93. m_procedure_linkage_table_offset = entry.ptr();
  94. break;
  95. case DT_PLTRELSZ:
  96. m_size_of_plt_relocation_entry_list = entry.val();
  97. break;
  98. case DT_PLTREL:
  99. m_procedure_linkage_table_relocation_type = entry.val();
  100. ASSERT(m_procedure_linkage_table_relocation_type & (DT_REL | DT_RELA));
  101. break;
  102. case DT_JMPREL:
  103. m_plt_relocation_offset_location = entry.ptr();
  104. break;
  105. case DT_RELA:
  106. case DT_REL:
  107. m_relocation_table_offset = entry.ptr();
  108. break;
  109. case DT_RELASZ:
  110. case DT_RELSZ:
  111. m_size_of_relocation_table = entry.val();
  112. break;
  113. case DT_RELAENT:
  114. case DT_RELENT:
  115. m_size_of_relocation_entry = entry.val();
  116. break;
  117. case DT_RELACOUNT:
  118. case DT_RELCOUNT:
  119. m_number_of_relocations = entry.val();
  120. break;
  121. case DT_FLAGS:
  122. m_dt_flags = entry.val();
  123. break;
  124. case DT_TEXTREL:
  125. m_dt_flags |= DF_TEXTREL; // This tag seems to exist for legacy reasons only?
  126. break;
  127. default:
  128. dbgprintf("ELFDynamicObject: DYNAMIC tag handling not implemented for DT_%s\n", name_for_dtag(entry.tag()));
  129. printf("ELFDynamicObject: DYNAMIC tag handling not implemented for DT_%s\n", name_for_dtag(entry.tag()));
  130. ASSERT_NOT_REACHED(); // FIXME: Maybe just break out here and return false?
  131. break;
  132. }
  133. return IterationDecision::Continue;
  134. });
  135. auto hash_section_address = hash_section().address().as_ptr();
  136. auto num_hash_chains = ((u32*)hash_section_address)[1];
  137. m_symbol_count = num_hash_chains;
  138. }
  139. const ELFDynamicObject::Relocation ELFDynamicObject::RelocationSection::relocation(unsigned index) const
  140. {
  141. ASSERT(index < entry_count());
  142. unsigned offset_in_section = index * entry_size();
  143. auto relocation_address = (Elf32_Rel*)address().offset(offset_in_section).as_ptr();
  144. return Relocation(m_dynamic, *relocation_address, offset_in_section);
  145. }
  146. const ELFDynamicObject::Relocation ELFDynamicObject::RelocationSection::relocation_at_offset(unsigned offset) const
  147. {
  148. ASSERT(offset <= (m_section_size_bytes - m_entry_size));
  149. auto relocation_address = (Elf32_Rel*)address().offset(offset).as_ptr();
  150. return Relocation(m_dynamic, *relocation_address, offset);
  151. }
  152. const ELFDynamicObject::Symbol ELFDynamicObject::symbol(unsigned index) const
  153. {
  154. auto symbol_section = Section(*this, m_symbol_table_offset, (m_symbol_count * m_size_of_symbol_table_entry), m_size_of_symbol_table_entry, "DT_SYMTAB");
  155. auto symbol_entry = (Elf32_Sym*)symbol_section.address().offset(index * symbol_section.entry_size()).as_ptr();
  156. return Symbol(*this, index, *symbol_entry);
  157. }
  158. const ELFDynamicObject::Section ELFDynamicObject::init_section() const
  159. {
  160. return Section(*this, m_init_offset, sizeof(void (*)()), sizeof(void (*)()), "DT_INIT");
  161. }
  162. const ELFDynamicObject::Section ELFDynamicObject::fini_section() const
  163. {
  164. return Section(*this, m_fini_offset, sizeof(void (*)()), sizeof(void (*)()), "DT_FINI");
  165. }
  166. const ELFDynamicObject::Section ELFDynamicObject::init_array_section() const
  167. {
  168. return Section(*this, m_init_array_offset, m_init_array_size, sizeof(void (*)()), "DT_INIT_ARRAY");
  169. }
  170. const ELFDynamicObject::Section ELFDynamicObject::fini_array_section() const
  171. {
  172. return Section(*this, m_fini_array_offset, m_fini_array_size, sizeof(void (*)()), "DT_FINI_ARRAY");
  173. }
  174. const ELFDynamicObject::HashSection ELFDynamicObject::hash_section() const
  175. {
  176. return HashSection(Section(*this, m_hash_table_offset, 0, 0, "DT_HASH"), HashType::SYSV);
  177. }
  178. const ELFDynamicObject::RelocationSection ELFDynamicObject::relocation_section() const
  179. {
  180. return RelocationSection(Section(*this, m_relocation_table_offset, m_size_of_relocation_table, m_size_of_relocation_entry, "DT_REL"));
  181. }
  182. const ELFDynamicObject::RelocationSection ELFDynamicObject::plt_relocation_section() const
  183. {
  184. return RelocationSection(Section(*this, m_plt_relocation_offset_location, m_size_of_plt_relocation_entry_list, m_size_of_relocation_entry, "DT_JMPREL"));
  185. }
  186. u32 ELFDynamicObject::HashSection::calculate_elf_hash(const char* name) const
  187. {
  188. // SYSV ELF hash algorithm
  189. // Note that the GNU HASH algorithm has less collisions
  190. uint32_t hash = 0;
  191. uint32_t top_nibble_of_hash = 0;
  192. while (*name != '\0') {
  193. hash = hash << 4;
  194. hash += *name;
  195. name++;
  196. top_nibble_of_hash = hash & 0xF0000000U;
  197. if (top_nibble_of_hash != 0)
  198. hash ^= top_nibble_of_hash >> 24;
  199. hash &= ~top_nibble_of_hash;
  200. }
  201. return hash;
  202. }
  203. u32 ELFDynamicObject::HashSection::calculate_gnu_hash(const char*) const
  204. {
  205. // FIXME: Implement the GNU hash algorithm
  206. ASSERT_NOT_REACHED();
  207. }
  208. const ELFDynamicObject::Symbol ELFDynamicObject::HashSection::lookup_symbol(const char* name) const
  209. {
  210. // FIXME: If we enable gnu hash in the compiler, we should use that here instead
  211. // The algo is way better with less collisions
  212. u32 hash_value = (this->*(m_hash_function))(name);
  213. u32* hash_table_begin = (u32*)address().as_ptr();
  214. size_t num_buckets = hash_table_begin[0];
  215. // This is here for completeness, but, since we're using the fact that every chain
  216. // will end at chain 0 (which means 'not found'), we don't need to check num_chains.
  217. // Interestingly, num_chains is required to be num_symbols
  218. //size_t num_chains = hash_table_begin[1];
  219. u32* buckets = &hash_table_begin[2];
  220. u32* chains = &buckets[num_buckets];
  221. for (u32 i = buckets[hash_value % num_buckets]; i; i = chains[i]) {
  222. auto symbol = m_dynamic.symbol(i);
  223. if (strcmp(name, symbol.name()) == 0) {
  224. #ifdef DYNAMIC_LOAD_DEBUG
  225. dbgprintf("Returning dynamic symbol with index %d for %s: %p\n", i, symbol.name(), symbol.address());
  226. #endif
  227. return symbol;
  228. }
  229. }
  230. return m_dynamic.the_undefined_symbol();
  231. }
  232. const char* ELFDynamicObject::symbol_string_table_string(Elf32_Word index) const
  233. {
  234. return (const char*)base_address().offset(m_string_table_offset + index).as_ptr();
  235. }
  236. static const char* name_for_dtag(Elf32_Sword d_tag)
  237. {
  238. switch (d_tag) {
  239. case DT_NULL:
  240. return "NULL"; /* marks end of _DYNAMIC array */
  241. case DT_NEEDED:
  242. return "NEEDED"; /* string table offset of needed lib */
  243. case DT_PLTRELSZ:
  244. return "PLTRELSZ"; /* size of relocation entries in PLT */
  245. case DT_PLTGOT:
  246. return "PLTGOT"; /* address PLT/GOT */
  247. case DT_HASH:
  248. return "HASH"; /* address of symbol hash table */
  249. case DT_STRTAB:
  250. return "STRTAB"; /* address of string table */
  251. case DT_SYMTAB:
  252. return "SYMTAB"; /* address of symbol table */
  253. case DT_RELA:
  254. return "RELA"; /* address of relocation table */
  255. case DT_RELASZ:
  256. return "RELASZ"; /* size of relocation table */
  257. case DT_RELAENT:
  258. return "RELAENT"; /* size of relocation entry */
  259. case DT_STRSZ:
  260. return "STRSZ"; /* size of string table */
  261. case DT_SYMENT:
  262. return "SYMENT"; /* size of symbol table entry */
  263. case DT_INIT:
  264. return "INIT"; /* address of initialization func. */
  265. case DT_FINI:
  266. return "FINI"; /* address of termination function */
  267. case DT_SONAME:
  268. return "SONAME"; /* string table offset of shared obj */
  269. case DT_RPATH:
  270. return "RPATH"; /* string table offset of library search path */
  271. case DT_SYMBOLIC:
  272. return "SYMBOLIC"; /* start sym search in shared obj. */
  273. case DT_REL:
  274. return "REL"; /* address of rel. tbl. w addends */
  275. case DT_RELSZ:
  276. return "RELSZ"; /* size of DT_REL relocation table */
  277. case DT_RELENT:
  278. return "RELENT"; /* size of DT_REL relocation entry */
  279. case DT_PLTREL:
  280. return "PLTREL"; /* PLT referenced relocation entry */
  281. case DT_DEBUG:
  282. return "DEBUG"; /* bugger */
  283. case DT_TEXTREL:
  284. return "TEXTREL"; /* Allow rel. mod. to unwritable seg */
  285. case DT_JMPREL:
  286. return "JMPREL"; /* add. of PLT's relocation entries */
  287. case DT_BIND_NOW:
  288. return "BIND_NOW"; /* Bind now regardless of env setting */
  289. case DT_INIT_ARRAY:
  290. return "INIT_ARRAY"; /* address of array of init func */
  291. case DT_FINI_ARRAY:
  292. return "FINI_ARRAY"; /* address of array of term func */
  293. case DT_INIT_ARRAYSZ:
  294. return "INIT_ARRAYSZ"; /* size of array of init func */
  295. case DT_FINI_ARRAYSZ:
  296. return "FINI_ARRAYSZ"; /* size of array of term func */
  297. case DT_RUNPATH:
  298. return "RUNPATH"; /* strtab offset of lib search path */
  299. case DT_FLAGS:
  300. return "FLAGS"; /* Set of DF_* flags */
  301. case DT_ENCODING:
  302. return "ENCODING"; /* further DT_* follow encoding rules */
  303. case DT_PREINIT_ARRAY:
  304. return "PREINIT_ARRAY"; /* address of array of preinit func */
  305. case DT_PREINIT_ARRAYSZ:
  306. return "PREINIT_ARRAYSZ"; /* size of array of preinit func */
  307. case DT_LOOS:
  308. return "LOOS"; /* reserved range for OS */
  309. case DT_HIOS:
  310. return "HIOS"; /* specific dynamic array tags */
  311. case DT_LOPROC:
  312. return "LOPROC"; /* reserved range for processor */
  313. case DT_HIPROC:
  314. return "HIPROC"; /* specific dynamic array tags */
  315. case DT_GNU_HASH:
  316. return "GNU_HASH"; /* address of GNU hash table */
  317. case DT_RELACOUNT:
  318. return "RELACOUNT"; /* if present, number of RELATIVE */
  319. case DT_RELCOUNT:
  320. return "RELCOUNT"; /* relocs, which must come first */
  321. case DT_FLAGS_1:
  322. return "FLAGS_1";
  323. default:
  324. return "??";
  325. }
  326. }