DynamicLoader.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Copyright (c) 2019-2020, Andrew Kaster <akaster@serenityos.org>
  3. * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/Assertions.h>
  9. #include <AK/ByteString.h>
  10. #include <AK/OwnPtr.h>
  11. #include <AK/RefCounted.h>
  12. #include <LibELF/DynamicObject.h>
  13. #include <LibELF/ELFABI.h>
  14. #include <LibELF/Image.h>
  15. #include <bits/dlfcn_integration.h>
  16. #include <sys/mman.h>
  17. namespace ELF {
  18. class LoadedSegment {
  19. public:
  20. LoadedSegment(VirtualAddress address, size_t size)
  21. : m_address(address)
  22. , m_size(size)
  23. {
  24. }
  25. VirtualAddress address() const { return m_address; }
  26. size_t size() const { return m_size; }
  27. private:
  28. VirtualAddress m_address;
  29. size_t m_size;
  30. };
  31. enum class ShouldInitializeWeak {
  32. Yes,
  33. No
  34. };
  35. enum class ShouldCallIfuncResolver {
  36. Yes,
  37. No
  38. };
  39. extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset);
  40. class DynamicLoader : public RefCounted<DynamicLoader> {
  41. public:
  42. static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> try_create(int fd, ByteString filepath);
  43. ~DynamicLoader();
  44. ByteString const& filepath() const { return m_filepath; }
  45. bool is_valid() const { return m_valid; }
  46. // Load a full ELF image from file into the current process and create an DynamicObject
  47. // from the SHT_DYNAMIC in the file.
  48. // Note that the DynamicObject will not be linked yet. Callers are responsible for calling link() to finish it.
  49. RefPtr<DynamicObject> map();
  50. bool link(unsigned flags);
  51. // Stage 2 of loading: dynamic object loading and primary relocations
  52. bool load_stage_2(unsigned flags);
  53. // Stage 3 of loading: lazy relocations
  54. Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> load_stage_3(unsigned flags);
  55. // Stage 4 of loading: initializers
  56. void load_stage_4();
  57. void set_tls_offset(size_t offset) { m_tls_offset = offset; }
  58. size_t tls_size_of_current_object() const { return m_tls_size_of_current_object; }
  59. size_t tls_alignment_of_current_object() const { return m_tls_alignment_of_current_object; }
  60. size_t tls_offset() const { return m_tls_offset; }
  61. const ELF::Image& image() const { return *m_elf_image; }
  62. template<typename F>
  63. void for_each_needed_library(F) const;
  64. VirtualAddress base_address() const { return m_base_address; }
  65. Vector<LoadedSegment> const text_segments() const { return m_text_segments; }
  66. bool is_dynamic() const { return image().is_dynamic(); }
  67. static Optional<DynamicObject::SymbolLookupResult> lookup_symbol(const ELF::DynamicObject::Symbol&);
  68. void copy_initial_tls_data_into(ByteBuffer& buffer) const;
  69. DynamicObject const& dynamic_object() const;
  70. bool is_fully_relocated() const { return m_fully_relocated; }
  71. bool is_fully_initialized() const { return m_fully_initialized; }
  72. private:
  73. DynamicLoader(int fd, ByteString filepath, void* file_data, size_t file_size);
  74. class ProgramHeaderRegion {
  75. public:
  76. void set_program_header(Elf_Phdr const& header) { m_program_header = header; }
  77. // Information from ELF Program header
  78. u32 type() const { return m_program_header.p_type; }
  79. u32 flags() const { return m_program_header.p_flags; }
  80. u32 offset() const { return m_program_header.p_offset; }
  81. VirtualAddress desired_load_address() const { return VirtualAddress(m_program_header.p_vaddr); }
  82. u32 size_in_memory() const { return m_program_header.p_memsz; }
  83. u32 size_in_image() const { return m_program_header.p_filesz; }
  84. u32 alignment() const { return m_program_header.p_align; }
  85. bool is_readable() const { return flags() & PF_R; }
  86. bool is_writable() const { return flags() & PF_W; }
  87. bool is_executable() const { return flags() & PF_X; }
  88. bool is_tls_template() const { return type() == PT_TLS; }
  89. bool is_load() const { return type() == PT_LOAD; }
  90. bool is_dynamic() const { return type() == PT_DYNAMIC; }
  91. bool is_relro() const { return type() == PT_GNU_RELRO; }
  92. private:
  93. Elf_Phdr m_program_header; // Explicitly a copy of the PHDR in the image
  94. };
  95. // Stage 1
  96. void load_program_headers();
  97. // Stage 2
  98. void do_main_relocations();
  99. // Stage 3
  100. void do_lazy_relocations();
  101. void setup_plt_trampoline();
  102. // Stage 4
  103. void call_object_init_functions();
  104. bool validate();
  105. friend FlatPtr _fixup_plt_entry(DynamicObject*, u32);
  106. enum class RelocationResult : uint8_t {
  107. Failed = 0,
  108. Success = 1,
  109. ResolveLater = 2,
  110. CallIfuncResolver = 3,
  111. };
  112. struct CachedLookupResult {
  113. DynamicObject::Symbol symbol;
  114. Optional<DynamicObject::SymbolLookupResult> result;
  115. };
  116. RelocationResult do_direct_relocation(DynamicObject::Relocation const&, Optional<CachedLookupResult>&, ShouldInitializeWeak, ShouldCallIfuncResolver);
  117. // Will be called from _fixup_plt_entry, as part of the PLT trampoline
  118. static RelocationResult do_plt_relocation(DynamicObject::Relocation const&, ShouldCallIfuncResolver);
  119. void do_relr_relocations();
  120. void find_tls_size_and_alignment();
  121. ByteString m_filepath;
  122. size_t m_file_size { 0 };
  123. int m_image_fd { -1 };
  124. void* m_file_data { nullptr };
  125. OwnPtr<ELF::Image> m_elf_image;
  126. bool m_valid { true };
  127. RefPtr<DynamicObject> m_dynamic_object;
  128. VirtualAddress m_base_address;
  129. Vector<LoadedSegment> m_text_segments;
  130. VirtualAddress m_relro_segment_address;
  131. size_t m_relro_segment_size { 0 };
  132. VirtualAddress m_dynamic_section_address;
  133. ssize_t m_tls_offset { 0 };
  134. size_t m_tls_size_of_current_object { 0 };
  135. size_t m_tls_alignment_of_current_object { 0 };
  136. Vector<DynamicObject::Relocation> m_unresolved_relocations;
  137. Vector<DynamicObject::Relocation> m_direct_ifunc_relocations;
  138. Vector<DynamicObject::Relocation> m_plt_ifunc_relocations;
  139. mutable RefPtr<DynamicObject> m_cached_dynamic_object;
  140. bool m_fully_relocated { false };
  141. bool m_fully_initialized { false };
  142. };
  143. template<typename F>
  144. void DynamicLoader::for_each_needed_library(F func) const
  145. {
  146. dynamic_object().for_each_needed_library(move(func));
  147. }
  148. } // end namespace ELF