Serenity Operating System
at master 175 lines 5.6 kB view raw
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 8#pragma once 9 10#include <AK/Assertions.h> 11#include <AK/DeprecatedString.h> 12#include <AK/OwnPtr.h> 13#include <AK/RefCounted.h> 14#include <LibC/elf.h> 15#include <LibELF/DynamicObject.h> 16#include <LibELF/Image.h> 17#include <bits/dlfcn_integration.h> 18#include <sys/mman.h> 19 20namespace ELF { 21 22class LoadedSegment { 23public: 24 LoadedSegment(VirtualAddress address, size_t size) 25 : m_address(address) 26 , m_size(size) 27 { 28 } 29 30 VirtualAddress address() const { return m_address; } 31 size_t size() const { return m_size; } 32 33private: 34 VirtualAddress m_address; 35 size_t m_size; 36}; 37 38enum class ShouldInitializeWeak { 39 Yes, 40 No 41}; 42 43class DynamicLoader : public RefCounted<DynamicLoader> { 44public: 45 static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> try_create(int fd, DeprecatedString filepath); 46 ~DynamicLoader(); 47 48 DeprecatedString const& filepath() const { return m_filepath; } 49 50 bool is_valid() const { return m_valid; } 51 52 // Load a full ELF image from file into the current process and create an DynamicObject 53 // from the SHT_DYNAMIC in the file. 54 // Note that the DynamicObject will not be linked yet. Callers are responsible for calling link() to finish it. 55 RefPtr<DynamicObject> map(); 56 57 bool link(unsigned flags); 58 59 // Stage 2 of loading: dynamic object loading and primary relocations 60 bool load_stage_2(unsigned flags); 61 62 // Stage 3 of loading: lazy relocations 63 Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> load_stage_3(unsigned flags); 64 65 // Stage 4 of loading: initializers 66 void load_stage_4(); 67 68 void set_tls_offset(size_t offset) { m_tls_offset = offset; }; 69 size_t tls_size_of_current_object() const { return m_tls_size_of_current_object; } 70 size_t tls_alignment_of_current_object() const { return m_tls_alignment_of_current_object; } 71 size_t tls_offset() const { return m_tls_offset; } 72 const ELF::Image& image() const { return *m_elf_image; } 73 74 template<typename F> 75 void for_each_needed_library(F) const; 76 77 VirtualAddress base_address() const { return m_base_address; } 78 Vector<LoadedSegment> const text_segments() const { return m_text_segments; } 79 bool is_dynamic() const { return image().is_dynamic(); } 80 81 static Optional<DynamicObject::SymbolLookupResult> lookup_symbol(const ELF::DynamicObject::Symbol&); 82 void copy_initial_tls_data_into(ByteBuffer& buffer) const; 83 84 DynamicObject const& dynamic_object() const; 85 86 bool is_fully_relocated() const { return m_fully_relocated; } 87 bool is_fully_initialized() const { return m_fully_initialized; } 88 89private: 90 DynamicLoader(int fd, DeprecatedString filepath, void* file_data, size_t file_size); 91 92 class ProgramHeaderRegion { 93 public: 94 void set_program_header(const ElfW(Phdr) & header) { m_program_header = header; } 95 96 // Information from ELF Program header 97 u32 type() const { return m_program_header.p_type; } 98 u32 flags() const { return m_program_header.p_flags; } 99 u32 offset() const { return m_program_header.p_offset; } 100 VirtualAddress desired_load_address() const { return VirtualAddress(m_program_header.p_vaddr); } 101 u32 size_in_memory() const { return m_program_header.p_memsz; } 102 u32 size_in_image() const { return m_program_header.p_filesz; } 103 u32 alignment() const { return m_program_header.p_align; } 104 bool is_readable() const { return flags() & PF_R; } 105 bool is_writable() const { return flags() & PF_W; } 106 bool is_executable() const { return flags() & PF_X; } 107 bool is_tls_template() const { return type() == PT_TLS; } 108 bool is_load() const { return type() == PT_LOAD; } 109 bool is_dynamic() const { return type() == PT_DYNAMIC; } 110 bool is_relro() const { return type() == PT_GNU_RELRO; } 111 112 private: 113 ElfW(Phdr) m_program_header; // Explicitly a copy of the PHDR in the image 114 }; 115 116 // Stage 1 117 void load_program_headers(); 118 119 // Stage 2 120 void do_main_relocations(); 121 122 // Stage 3 123 void do_lazy_relocations(); 124 void setup_plt_trampoline(); 125 126 // Stage 4 127 void call_object_init_functions(); 128 129 bool validate(); 130 131 enum class RelocationResult : uint8_t { 132 Failed = 0, 133 Success = 1, 134 ResolveLater = 2, 135 }; 136 RelocationResult do_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak should_initialize_weak); 137 void do_relr_relocations(); 138 void find_tls_size_and_alignment(); 139 140 DeprecatedString m_filepath; 141 size_t m_file_size { 0 }; 142 int m_image_fd { -1 }; 143 void* m_file_data { nullptr }; 144 OwnPtr<ELF::Image> m_elf_image; 145 bool m_valid { true }; 146 147 RefPtr<DynamicObject> m_dynamic_object; 148 149 VirtualAddress m_base_address; 150 Vector<LoadedSegment> m_text_segments; 151 152 VirtualAddress m_relro_segment_address; 153 size_t m_relro_segment_size { 0 }; 154 155 VirtualAddress m_dynamic_section_address; 156 157 ssize_t m_tls_offset { 0 }; 158 size_t m_tls_size_of_current_object { 0 }; 159 size_t m_tls_alignment_of_current_object { 0 }; 160 161 Vector<DynamicObject::Relocation> m_unresolved_relocations; 162 163 mutable RefPtr<DynamicObject> m_cached_dynamic_object; 164 165 bool m_fully_relocated { false }; 166 bool m_fully_initialized { false }; 167}; 168 169template<typename F> 170void DynamicLoader::for_each_needed_library(F func) const 171{ 172 dynamic_object().for_each_needed_library(move(func)); 173} 174 175} // end namespace ELF