ELFDynamicObject.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. #include <AK/StringBuilder.h>
  2. #include <LibELF/ELFDynamicObject.h>
  3. #include <assert.h>
  4. #include <mman.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #define DYNAMIC_LOAD_DEBUG
  8. //#define DYNAMIC_LOAD_VERBOSE
  9. #ifdef DYNAMIC_LOAD_VERBOSE
  10. # define VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__)
  11. #else
  12. # define VERBOSE(fmt, ...) do { } while (0)
  13. #endif
  14. static bool s_always_bind_now = true;
  15. static const char* name_for_dtag(Elf32_Sword tag);
  16. // SYSV ELF hash algorithm
  17. // Note that the GNU HASH algorithm has less collisions
  18. static uint32_t calculate_elf_hash(const char* name)
  19. {
  20. uint32_t hash = 0;
  21. uint32_t top_nibble_of_hash = 0;
  22. while (*name != '\0') {
  23. hash = hash << 4;
  24. hash += *name;
  25. name++;
  26. top_nibble_of_hash = hash & 0xF0000000U;
  27. if (top_nibble_of_hash != 0)
  28. hash ^= top_nibble_of_hash >> 24;
  29. hash &= ~top_nibble_of_hash;
  30. }
  31. return hash;
  32. }
  33. NonnullRefPtr<ELFDynamicObject> ELFDynamicObject::construct(const char* filename, int fd, size_t size)
  34. {
  35. return adopt(*new ELFDynamicObject(filename, fd, size));
  36. }
  37. ELFDynamicObject::ELFDynamicObject(const char* filename, int fd, size_t size)
  38. : m_filename(filename)
  39. , m_file_size(size)
  40. , m_image_fd(fd)
  41. {
  42. String file_mmap_name = String::format("ELF_DYN: %s", m_filename.characters());
  43. m_file_mapping = mmap_with_name(nullptr, size, PROT_READ, MAP_PRIVATE, m_image_fd, 0, file_mmap_name.characters());
  44. if (MAP_FAILED == m_file_mapping) {
  45. m_valid = false;
  46. return;
  47. }
  48. m_image = AK::make<ELFImage>((u8*)m_file_mapping);
  49. m_valid = m_image->is_valid() && m_image->parse() && m_image->is_dynamic();
  50. if (!m_valid) {
  51. return;
  52. }
  53. const ELFImage::DynamicSection probably_dynamic_section = m_image->dynamic_section();
  54. if (StringView(".dynamic") != probably_dynamic_section.name() || probably_dynamic_section.type() != SHT_DYNAMIC) {
  55. m_valid = false;
  56. return;
  57. }
  58. }
  59. ELFDynamicObject::~ELFDynamicObject()
  60. {
  61. if (MAP_FAILED != m_file_mapping)
  62. munmap(m_file_mapping, m_file_size);
  63. }
  64. void ELFDynamicObject::dump()
  65. {
  66. auto dynamic_section = m_image->dynamic_section();
  67. StringBuilder builder;
  68. builder.append("\nd_tag tag_name value\n");
  69. size_t num_dynamic_sections = 0;
  70. dynamic_section.for_each_dynamic_entry([&](const ELFImage::DynamicSectionEntry& entry) {
  71. String name_field = String::format("(%s)", name_for_dtag(entry.tag()));
  72. builder.appendf("0x%08X %-17s0x%X\n", entry.tag(), name_field.characters(), entry.val());
  73. num_dynamic_sections++;
  74. return IterationDecision::Continue;
  75. });
  76. dbgprintf("Dynamic section at offset 0x%x contains %zu entries:\n", dynamic_section.offset(), num_dynamic_sections);
  77. dbgprintf(builder.to_string().characters());
  78. }
  79. void ELFDynamicObject::parse_dynamic_section()
  80. {
  81. auto dynamic_section = m_image->dynamic_section();
  82. dynamic_section.for_each_dynamic_entry([&](const ELFImage::DynamicSectionEntry& entry) {
  83. switch (entry.tag()) {
  84. case DT_INIT:
  85. m_init_offset = entry.ptr();
  86. break;
  87. case DT_FINI:
  88. m_fini_offset = entry.ptr();
  89. break;
  90. case DT_INIT_ARRAY:
  91. m_init_array_offset = entry.ptr();
  92. break;
  93. case DT_INIT_ARRAYSZ:
  94. m_init_array_size = entry.val();
  95. break;
  96. case DT_HASH:
  97. m_hash_table_offset = entry.ptr();
  98. break;
  99. case DT_SYMTAB:
  100. m_symbol_table_offset = entry.ptr();
  101. break;
  102. case DT_STRTAB:
  103. m_string_table_offset = entry.ptr();
  104. break;
  105. case DT_STRSZ:
  106. m_size_of_string_table = entry.val();
  107. break;
  108. case DT_SYMENT:
  109. m_size_of_symbol_table_entry = entry.val();
  110. break;
  111. case DT_PLTGOT:
  112. m_procedure_linkage_table_offset = entry.ptr();
  113. break;
  114. case DT_PLTRELSZ:
  115. m_size_of_plt_relocation_entry_list = entry.val();
  116. break;
  117. case DT_PLTREL:
  118. m_procedure_linkage_table_relocation_type = entry.val();
  119. ASSERT(m_procedure_linkage_table_relocation_type & (DT_REL | DT_RELA));
  120. break;
  121. case DT_JMPREL:
  122. m_plt_relocation_offset_location = entry.ptr();
  123. break;
  124. case DT_RELA:
  125. case DT_REL:
  126. m_relocation_table_offset = entry.ptr();
  127. break;
  128. case DT_RELASZ:
  129. case DT_RELSZ:
  130. m_size_of_relocation_table = entry.val();
  131. break;
  132. case DT_RELAENT:
  133. case DT_RELENT:
  134. m_size_of_relocation_entry = entry.val();
  135. break;
  136. case DT_RELACOUNT:
  137. case DT_RELCOUNT:
  138. m_number_of_relocations = entry.val();
  139. break;
  140. case DT_FLAGS:
  141. m_must_bind_now = entry.val() & DF_BIND_NOW;
  142. m_has_text_relocations = entry.val() & DF_TEXTREL;
  143. m_should_process_origin = entry.val() & DF_ORIGIN;
  144. m_has_static_thread_local_storage = entry.val() & DF_STATIC_TLS;
  145. m_requires_symbolic_symbol_resolution = entry.val() & DF_SYMBOLIC;
  146. break;
  147. case DT_TEXTREL:
  148. m_has_text_relocations = true; // This tag seems to exist for legacy reasons only?
  149. break;
  150. default:
  151. dbgprintf("ELFDynamicObject: DYNAMIC tag handling not implemented for DT_%s\n", name_for_dtag(entry.tag()));
  152. printf("ELFDynamicObject: DYNAMIC tag handling not implemented for DT_%s\n", name_for_dtag(entry.tag()));
  153. ASSERT_NOT_REACHED(); // FIXME: Maybe just break out here and return false?
  154. break;
  155. }
  156. return IterationDecision::Continue;
  157. });
  158. }
  159. typedef void (*InitFunc)();
  160. bool ELFDynamicObject::load(unsigned flags)
  161. {
  162. ASSERT(flags & RTLD_GLOBAL);
  163. ASSERT(flags & RTLD_LAZY);
  164. #ifdef DYNAMIC_LOAD_DEBUG
  165. dump();
  166. #endif
  167. #ifdef DYNAMIC_LOAD_VERBOSE
  168. m_image->dump();
  169. #endif
  170. parse_dynamic_section();
  171. // FIXME: be more flexible?
  172. size_t total_required_allocation_size = 0;
  173. // FIXME: Can we re-use ELFLoader? This and what follows looks a lot like what's in there...
  174. // With the exception of using desired_load_address().offset(text_segment_begin)
  175. // It seems kinda gross to expect the program headers to be in a specific order..
  176. m_image->for_each_program_header([&](const ELFImage::ProgramHeader& program_header) {
  177. ProgramHeaderRegion new_region(program_header.raw_header());
  178. if (new_region.is_load())
  179. total_required_allocation_size += new_region.required_load_size();
  180. m_program_header_regions.append(move(new_region));
  181. auto& region = m_program_header_regions.last();
  182. if (region.is_tls_template())
  183. m_tls_region = &region;
  184. else if (region.is_load()) {
  185. if (region.is_executable())
  186. m_text_region = &region;
  187. else
  188. m_data_region = &region;
  189. }
  190. });
  191. ASSERT(m_text_region && m_data_region);
  192. // Process regions in order: .text, .data, .tls
  193. auto* region = m_text_region;
  194. void* text_segment_begin = mmap_with_name(nullptr, region->required_load_size(), region->mmap_prot(), MAP_PRIVATE, m_image_fd, region->offset(), String::format(".text: %s", m_filename.characters()).characters());
  195. size_t text_segment_size = region->required_load_size();
  196. region->set_base_address(VirtualAddress { (u32)text_segment_begin });
  197. region->set_load_address(VirtualAddress { (u32)text_segment_begin });
  198. region = m_data_region;
  199. void* data_segment_begin = mmap_with_name((u8*)text_segment_begin + text_segment_size, region->required_load_size(), region->mmap_prot(), MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, String::format(".data: %s", m_filename.characters()).characters());
  200. size_t data_segment_size = region->required_load_size();
  201. VirtualAddress data_segment_actual_addr = region->desired_load_address().offset((u32)text_segment_begin);
  202. region->set_base_address(VirtualAddress { (u32)text_segment_begin });
  203. region->set_load_address(data_segment_actual_addr);
  204. memcpy(data_segment_actual_addr.as_ptr(), (u8*)m_file_mapping + region->offset(), region->size_in_image());
  205. if (m_tls_region) {
  206. region = m_data_region;
  207. VirtualAddress tls_segment_actual_addr = region->desired_load_address().offset((u32)text_segment_begin);
  208. region->set_base_address(VirtualAddress { (u32)text_segment_begin });
  209. region->set_load_address(tls_segment_actual_addr);
  210. memcpy(tls_segment_actual_addr.as_ptr(), (u8*)m_file_mapping + region->offset(), region->size_in_image());
  211. }
  212. // sanity check
  213. u8* end_of_in_memory_image = (u8*)data_segment_begin + data_segment_size;
  214. ASSERT((ptrdiff_t)total_required_allocation_size == (ptrdiff_t)(end_of_in_memory_image - (u8*)text_segment_begin));
  215. if (m_has_text_relocations) {
  216. if (0 > mprotect(m_text_region->load_address().as_ptr(), m_text_region->required_load_size(), PROT_READ | PROT_WRITE)) {
  217. perror("mprotect"); // FIXME: dlerror?
  218. return false;
  219. }
  220. }
  221. do_relocations();
  222. #ifdef DYNAMIC_LOAD_DEBUG
  223. dbgprintf("Done relocating!\n");
  224. #endif
  225. // FIXME: PLT patching doesn't seem to work as expected.
  226. // Need to dig into the spec to see what we're doing wrong
  227. // Hopefully it won't need an assembly entry point... :/
  228. /// For now we can just BIND_NOW every time
  229. // This should be the address of section ".got.plt"
  230. const ELFImage::Section& got_section = m_image->lookup_section(".got.plt");
  231. VirtualAddress got_address = m_text_region->load_address().offset(got_section.address());
  232. u32* got_u32_ptr = reinterpret_cast<u32*>(got_address.as_ptr());
  233. got_u32_ptr[1] = (u32)this;
  234. got_u32_ptr[2] = (u32)&ELFDynamicObject::patch_plt_entry;
  235. #ifdef DYNAMIC_LOAD_DEBUG
  236. dbgprintf("Set GOT PLT entries at %p: [0] = %p [1] = %p, [2] = %p\n", got_u32_ptr, got_u32_ptr[0], got_u32_ptr[1], got_u32_ptr[2]);
  237. #endif
  238. // Clean up our setting of .text to PROT_READ | PROT_WRITE
  239. if (m_has_text_relocations) {
  240. if (0 > mprotect(m_text_region->load_address().as_ptr(), m_text_region->required_load_size(), PROT_READ | PROT_EXEC)) {
  241. perror("mprotect"); // FIXME: dlerror?
  242. return false;
  243. }
  244. }
  245. u8* load_addr = m_text_region->load_address().as_ptr();
  246. InitFunc init_function = (InitFunc)(load_addr + m_init_offset);
  247. #ifdef DYNAMIC_LOAD_DEBUG
  248. dbgprintf("Calling DT_INIT at %p\n", init_function);
  249. #endif
  250. // FIXME:
  251. // Disassembly of section .init:
  252. //
  253. // 00007e98 <_init>:
  254. // 7e98: 55 push ebp
  255. //
  256. // Where da ret at? related to -nostartfiles for sure...
  257. //(init_function)();
  258. InitFunc* init_begin = (InitFunc*)(load_addr + m_init_array_offset);
  259. u32 init_end = (u32)((u8*)init_begin + m_init_array_size);
  260. while ((u32)init_begin < init_end) {
  261. // Andriod sources claim that these can be -1, to be ignored.
  262. // 0 definitely shows up. Apparently 0/-1 are valid? Confusing.
  263. if (!*init_begin || ((i32)*init_begin == -1))
  264. continue;
  265. #ifdef DYNAMIC_LOAD_DEBUG
  266. dbgprintf("Calling DT_INITARRAY entry at %p\n", *init_begin);
  267. #endif
  268. (*init_begin)();
  269. ++init_begin;
  270. }
  271. #ifdef DYNAMIC_LOAD_DEBUG
  272. dbgprintf("Loaded %s\n", m_filename.characters());
  273. #endif
  274. // FIXME: return false sometimes? missing symbol etc
  275. return true;
  276. }
  277. void* ELFDynamicObject::symbol_for_name(const char* name)
  278. {
  279. // FIXME: If we enable gnu hash in the compiler, we should use that here instead
  280. // The algo is way better with less collisions
  281. uint32_t hash_value = calculate_elf_hash(name);
  282. u8* load_addr = m_text_region->load_address().as_ptr();
  283. // NOTE: We need to use the loaded hash/string/symbol tables here to get the right
  284. // addresses. The ones that are in the ELFImage won't cut it, they aren't relocated
  285. u32* hash_table_begin = (u32*)(load_addr + m_hash_table_offset);
  286. Elf32_Sym* symtab = (Elf32_Sym*)(load_addr + m_symbol_table_offset);
  287. const char* strtab = (const char*)load_addr + m_string_table_offset;
  288. size_t num_buckets = hash_table_begin[0];
  289. // This is here for completeness, but, since we're using the fact that every chain
  290. // will end at chain 0 (which means 'not found'), we don't need to check num_chains.
  291. // Interestingly, num_chains is required to be num_symbols
  292. //size_t num_chains = hash_table_begin[1];
  293. u32* buckets = &hash_table_begin[2];
  294. u32* chains = &buckets[num_buckets];
  295. for (u32 i = buckets[hash_value % num_buckets]; i; i = chains[i]) {
  296. if (strcmp(name, strtab + symtab[i].st_name) == 0) {
  297. void* retval = load_addr + symtab[i].st_value;
  298. #ifdef DYNAMIC_LOAD_DEBUG
  299. dbgprintf("Returning dynamic symbol with index %d for %s: %p\n", i, strtab + symtab[i].st_name, retval);
  300. #endif
  301. return retval;
  302. }
  303. }
  304. return nullptr;
  305. }
  306. // offset is from PLT entry
  307. // Tag is inserted into GOT #2 for 'this' DSO (literally the this pointer)
  308. void ELFDynamicObject::patch_plt_entry(u32 got_offset, void* dso_got_tag)
  309. {
  310. // FIXME: This is never called :(
  311. CRASH();
  312. dbgprintf("------ PATCHING PLT ENTRY -------");
  313. // NOTE: We put 'this' into the GOT when we loaded it into memory
  314. auto* dynamic_object_object = reinterpret_cast<ELFDynamicObject*>(dso_got_tag);
  315. // FIXME: might actually be a RelA, check m_plt_relocation_type
  316. // u32 base_addr_offset = dynamic_object_object->m_relocation_table_offset + got_offset;
  317. // Elf32_Rel relocation = *reinterpret_cast<Elf32_Rel*>(&((u8*)dynamic_object_object->m_file_mapping)[base_addr_offset]);
  318. u32 relocation_index = got_offset / dynamic_object_object->m_size_of_relocation_entry;
  319. auto relocation = dynamic_object_object->m_image->dynamic_relocation_section().relocation(relocation_index);
  320. ASSERT(relocation.type() == R_386_JMP_SLOT);
  321. auto sym = relocation.symbol();
  322. auto* text_load_address = dynamic_object_object->m_text_region->load_address().as_ptr();
  323. u8* relocation_address = text_load_address + relocation.offset();
  324. if (0 > mprotect(text_load_address, dynamic_object_object->m_text_region->required_load_size(), PROT_READ | PROT_WRITE)) {
  325. ASSERT_NOT_REACHED(); // uh oh, no can do boss
  326. }
  327. dbgprintf("Found relocation address: %p for %s", relocation_address, sym.name());
  328. *(u32*)relocation_address = (u32)(text_load_address + sym.value());
  329. if (0 > mprotect(text_load_address, dynamic_object_object->m_text_region->required_load_size(), PROT_READ | PROT_EXEC)) {
  330. ASSERT_NOT_REACHED(); // uh oh, no can do boss
  331. }
  332. CRASH();
  333. // FIXME: Call the relocated method here?
  334. }
  335. void ELFDynamicObject::do_relocations()
  336. {
  337. auto dyn_relocation_section = m_image->dynamic_relocation_section();
  338. if (StringView(".rel.dyn") != dyn_relocation_section.name() || SHT_REL != dyn_relocation_section.type()) {
  339. ASSERT_NOT_REACHED();
  340. }
  341. u8* load_base_address = m_text_region->base_address().as_ptr();
  342. int i = -1;
  343. // FIXME: We should really bail on undefined symbols here. (but, there's some TLS vars that are currently undef soooo.... :) )
  344. dyn_relocation_section.for_each_relocation([&](const ELFImage::DynamicRelocation& relocation) {
  345. ++i;
  346. VERBOSE("====== RELOCATION %d: offset 0x%08X, type %d, symidx %08X\n", i, relocation.offset(), relocation.type(), relocation.symbol_index());
  347. u32* patch_ptr = (u32*)(load_base_address + relocation.offset());
  348. switch (relocation.type()) {
  349. case R_386_NONE:
  350. // Apparently most loaders will just skip these?
  351. // Seems if the 'link editor' generates one something is funky with your code
  352. VERBOSE("None relocation. No symbol, no nothin.\n");
  353. break;
  354. case R_386_32: {
  355. auto symbol = relocation.symbol();
  356. VERBOSE("Absolute relocation: name: '%s', value: %p\n", symbol.name(), symbol.value());
  357. if (symbol.bind() == STB_LOCAL) {
  358. u32 symbol_address = symbol.section().address() + symbol.value();
  359. *patch_ptr += symbol_address;
  360. } else if (symbol.bind() == STB_GLOBAL) {
  361. u32 symbol_address = symbol.value() + (u32)load_base_address;
  362. *patch_ptr += symbol_address;
  363. } else if (symbol.bind() == STB_WEAK) {
  364. // FIXME: Handle weak symbols...
  365. dbgprintf("ELFDynamicObject: Ignoring weak symbol %s\n", symbol.name());
  366. } else {
  367. VERBOSE("Found new fun symbol bind value %d\n", symbol.bind());
  368. ASSERT_NOT_REACHED();
  369. }
  370. VERBOSE(" Symbol address: %p\n", *patch_ptr);
  371. break;
  372. }
  373. case R_386_PC32: {
  374. auto symbol = relocation.symbol();
  375. VERBOSE("PC-relative relocation: '%s', value: %p\n", symbol.name(), symbol.value());
  376. u32 relative_offset = (symbol.value() - relocation.offset());
  377. *patch_ptr += relative_offset;
  378. VERBOSE(" Symbol address: %p\n", *patch_ptr);
  379. break;
  380. }
  381. case R_386_GLOB_DAT: {
  382. auto symbol = relocation.symbol();
  383. VERBOSE("Global data relocation: '%s', value: %p\n", symbol.name(), symbol.value());
  384. u32 symbol_location = (u32)(m_data_region->base_address().as_ptr() + symbol.value());
  385. *patch_ptr = symbol_location;
  386. VERBOSE(" Symbol address: %p\n", *patch_ptr);
  387. break;
  388. }
  389. case R_386_RELATIVE: {
  390. // FIXME: According to the spec, R_386_relative ones must be done first.
  391. // We could explicitly do them first using m_number_of_relocatoins from DT_RELCOUNT
  392. // However, our compiler is nice enough to put them at the front of the relocations for us :)
  393. VERBOSE("Load address relocation at offset %X\n", relocation.offset());
  394. VERBOSE(" patch ptr == %p, adding load base address (%p) to it and storing %p\n", *patch_ptr, load_base_address, *patch_ptr + (u32)load_base_address);
  395. *patch_ptr += (u32)load_base_address; // + addend for RelA (addend for Rel is stored at addr)
  396. break;
  397. }
  398. case R_386_TLS_TPOFF: {
  399. VERBOSE("Relocation type: R_386_TLS_TPOFF at offset %X\n", relocation.offset());
  400. // FIXME: this can't be right? I have no idea what "negative offset into TLS storage" means...
  401. // FIXME: Check m_has_static_tls and do something different for dynamic TLS
  402. VirtualAddress tls_region_loctation = m_tls_region->desired_load_address();
  403. *patch_ptr = relocation.offset() - (u32)tls_region_loctation.as_ptr() - *patch_ptr;
  404. break;
  405. }
  406. default:
  407. // Raise the alarm! Someone needs to implement this relocation type
  408. dbgprintf("Found a new exciting relocation type %d\n", relocation.type());
  409. printf("ELFDynamicObject: Found unknown relocation type %d\n", relocation.type());
  410. ASSERT_NOT_REACHED();
  411. break;
  412. }
  413. return IterationDecision::Continue;
  414. });
  415. // FIXME: Or BIND_NOW flag passed in?
  416. if (m_must_bind_now || s_always_bind_now) {
  417. // FIXME: Why do we keep jumping to the entry in the GOT without going to our callback first?
  418. // that would make this s_always_bind_now redundant
  419. for (size_t idx = 0; idx < m_size_of_plt_relocation_entry_list; idx += m_size_of_relocation_entry) {
  420. VirtualAddress relocation_vaddr = m_text_region->load_address().offset(m_plt_relocation_offset_location).offset(idx);
  421. Elf32_Rel* jump_slot_relocation = (Elf32_Rel*)relocation_vaddr.as_ptr();
  422. ASSERT(ELF32_R_TYPE(jump_slot_relocation->r_info) == R_386_JMP_SLOT);
  423. auto sym = m_image->dynamic_symbol(ELF32_R_SYM(jump_slot_relocation->r_info));
  424. auto* image_base_address = m_text_region->base_address().as_ptr();
  425. u8* relocation_address = image_base_address + jump_slot_relocation->r_offset;
  426. u32 symbol_location = (u32)(image_base_address + sym.value());
  427. VERBOSE("ELFDynamicObject: Jump slot relocation: putting %s (%p) into PLT at %p\n", sym.name(), symbol_location, relocation_address);
  428. *(u32*)relocation_address = symbol_location;
  429. }
  430. }
  431. }
  432. u32 ELFDynamicObject::ProgramHeaderRegion::mmap_prot() const
  433. {
  434. int prot = 0;
  435. prot |= is_executable() ? PROT_EXEC : 0;
  436. prot |= is_readable() ? PROT_READ : 0;
  437. prot |= is_writable() ? PROT_WRITE : 0;
  438. return prot;
  439. }
  440. static const char* name_for_dtag(Elf32_Sword d_tag)
  441. {
  442. switch (d_tag) {
  443. case DT_NULL:
  444. return "NULL"; /* marks end of _DYNAMIC array */
  445. case DT_NEEDED:
  446. return "NEEDED"; /* string table offset of needed lib */
  447. case DT_PLTRELSZ:
  448. return "PLTRELSZ"; /* size of relocation entries in PLT */
  449. case DT_PLTGOT:
  450. return "PLTGOT"; /* address PLT/GOT */
  451. case DT_HASH:
  452. return "HASH"; /* address of symbol hash table */
  453. case DT_STRTAB:
  454. return "STRTAB"; /* address of string table */
  455. case DT_SYMTAB:
  456. return "SYMTAB"; /* address of symbol table */
  457. case DT_RELA:
  458. return "RELA"; /* address of relocation table */
  459. case DT_RELASZ:
  460. return "RELASZ"; /* size of relocation table */
  461. case DT_RELAENT:
  462. return "RELAENT"; /* size of relocation entry */
  463. case DT_STRSZ:
  464. return "STRSZ"; /* size of string table */
  465. case DT_SYMENT:
  466. return "SYMENT"; /* size of symbol table entry */
  467. case DT_INIT:
  468. return "INIT"; /* address of initialization func. */
  469. case DT_FINI:
  470. return "FINI"; /* address of termination function */
  471. case DT_SONAME:
  472. return "SONAME"; /* string table offset of shared obj */
  473. case DT_RPATH:
  474. return "RPATH"; /* string table offset of library search path */
  475. case DT_SYMBOLIC:
  476. return "SYMBOLIC"; /* start sym search in shared obj. */
  477. case DT_REL:
  478. return "REL"; /* address of rel. tbl. w addends */
  479. case DT_RELSZ:
  480. return "RELSZ"; /* size of DT_REL relocation table */
  481. case DT_RELENT:
  482. return "RELENT"; /* size of DT_REL relocation entry */
  483. case DT_PLTREL:
  484. return "PLTREL"; /* PLT referenced relocation entry */
  485. case DT_DEBUG:
  486. return "DEBUG"; /* bugger */
  487. case DT_TEXTREL:
  488. return "TEXTREL"; /* Allow rel. mod. to unwritable seg */
  489. case DT_JMPREL:
  490. return "JMPREL"; /* add. of PLT's relocation entries */
  491. case DT_BIND_NOW:
  492. return "BIND_NOW"; /* Bind now regardless of env setting */
  493. case DT_INIT_ARRAY:
  494. return "INIT_ARRAY"; /* address of array of init func */
  495. case DT_FINI_ARRAY:
  496. return "FINI_ARRAY"; /* address of array of term func */
  497. case DT_INIT_ARRAYSZ:
  498. return "INIT_ARRAYSZ"; /* size of array of init func */
  499. case DT_FINI_ARRAYSZ:
  500. return "FINI_ARRAYSZ"; /* size of array of term func */
  501. case DT_RUNPATH:
  502. return "RUNPATH"; /* strtab offset of lib search path */
  503. case DT_FLAGS:
  504. return "FLAGS"; /* Set of DF_* flags */
  505. case DT_ENCODING:
  506. return "ENCODING"; /* further DT_* follow encoding rules */
  507. case DT_PREINIT_ARRAY:
  508. return "PREINIT_ARRAY"; /* address of array of preinit func */
  509. case DT_PREINIT_ARRAYSZ:
  510. return "PREINIT_ARRAYSZ"; /* size of array of preinit func */
  511. case DT_LOOS:
  512. return "LOOS"; /* reserved range for OS */
  513. case DT_HIOS:
  514. return "HIOS"; /* specific dynamic array tags */
  515. case DT_LOPROC:
  516. return "LOPROC"; /* reserved range for processor */
  517. case DT_HIPROC:
  518. return "HIPROC"; /* specific dynamic array tags */
  519. case DT_GNU_HASH:
  520. return "GNU_HASH"; /* address of GNU hash table */
  521. case DT_RELACOUNT:
  522. return "RELACOUNT"; /* if present, number of RELATIVE */
  523. case DT_RELCOUNT:
  524. return "RELCOUNT"; /* relocs, which must come first */
  525. case DT_FLAGS_1:
  526. return "FLAGS_1";
  527. default:
  528. return "??";
  529. }
  530. }