Serenity Operating System
at hosted 292 lines 10 kB view raw
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 27#pragma once 28 29#include <AK/Assertions.h> 30#include <LibBareMetal/Memory/VirtualAddress.h> 31#include <LibELF/exec_elf.h> 32 33class ELFDynamicObject { 34public: 35 explicit ELFDynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_address); 36 ~ELFDynamicObject(); 37 void dump() const; 38 39 class DynamicEntry; 40 class Section; 41 class RelocationSection; 42 class Symbol; 43 class Relocation; 44 class HashSection; 45 46 class DynamicEntry { 47 public: 48 DynamicEntry(const Elf32_Dyn& dyn) 49 : m_dyn(dyn) 50 { 51 } 52 53 ~DynamicEntry() {} 54 55 Elf32_Sword tag() const { return m_dyn.d_tag; } 56 Elf32_Addr ptr() const { return m_dyn.d_un.d_ptr; } 57 Elf32_Word val() const { return m_dyn.d_un.d_val; } 58 59 private: 60 const Elf32_Dyn& m_dyn; 61 }; 62 63 class Symbol { 64 public: 65 Symbol(const ELFDynamicObject& dynamic, unsigned index, const Elf32_Sym& sym) 66 : m_dynamic(dynamic) 67 , m_sym(sym) 68 , m_index(index) 69 { 70 } 71 72 ~Symbol() {} 73 74 const char* name() const { return m_dynamic.symbol_string_table_string(m_sym.st_name); } 75 unsigned section_index() const { return m_sym.st_shndx; } 76 unsigned value() const { return m_sym.st_value; } 77 unsigned size() const { return m_sym.st_size; } 78 unsigned index() const { return m_index; } 79 unsigned type() const { return ELF32_ST_TYPE(m_sym.st_info); } 80 unsigned bind() const { return ELF32_ST_BIND(m_sym.st_info); } 81 bool is_undefined() const { return this == &m_dynamic.the_undefined_symbol(); } 82 VirtualAddress address() const { return m_dynamic.base_address().offset(value()); } 83 84 private: 85 const ELFDynamicObject& m_dynamic; 86 const Elf32_Sym& m_sym; 87 const unsigned m_index; 88 }; 89 90 class Section { 91 public: 92 Section(const ELFDynamicObject& dynamic, unsigned section_offset, unsigned section_size_bytes, unsigned entry_size, const char* name) 93 : m_dynamic(dynamic) 94 , m_section_offset(section_offset) 95 , m_section_size_bytes(section_size_bytes) 96 , m_entry_size(entry_size) 97 , m_name(name) 98 { 99 } 100 ~Section() {} 101 102 const char* name() const { return m_name; } 103 unsigned offset() const { return m_section_offset; } 104 unsigned size() const { return m_section_size_bytes; } 105 unsigned entry_size() const { return m_entry_size; } 106 unsigned entry_count() const { return !entry_size() ? 0 : size() / entry_size(); } 107 VirtualAddress address() const { return m_dynamic.base_address().offset(m_section_offset); } 108 109 protected: 110 friend class RelocationSection; 111 friend class HashSection; 112 const ELFDynamicObject& m_dynamic; 113 unsigned m_section_offset; 114 unsigned m_section_size_bytes; 115 unsigned m_entry_size; 116 const char* m_name { nullptr }; 117 }; 118 119 class RelocationSection : public Section { 120 public: 121 RelocationSection(const Section& section) 122 : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) 123 { 124 } 125 unsigned relocation_count() const { return entry_count(); } 126 const Relocation relocation(unsigned index) const; 127 const Relocation relocation_at_offset(unsigned offset) const; 128 template<typename F> 129 void for_each_relocation(F) const; 130 }; 131 132 class Relocation { 133 public: 134 Relocation(const ELFDynamicObject& dynamic, const Elf32_Rel& rel, unsigned offset_in_section) 135 : m_dynamic(dynamic) 136 , m_rel(rel) 137 , m_offset_in_section(offset_in_section) 138 { 139 } 140 141 ~Relocation() {} 142 143 unsigned offset_in_section() const { return m_offset_in_section; } 144 unsigned offset() const { return m_rel.r_offset; } 145 unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); } 146 unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); } 147 const Symbol symbol() const { return m_dynamic.symbol(symbol_index()); } 148 VirtualAddress address() const { return m_dynamic.base_address().offset(offset()); } 149 150 private: 151 const ELFDynamicObject& m_dynamic; 152 const Elf32_Rel& m_rel; 153 const unsigned m_offset_in_section; 154 }; 155 156 enum class HashType { 157 SYSV, 158 GNU 159 }; 160 161 class HashSection : public Section { 162 public: 163 HashSection(const Section& section, HashType hash_type = HashType::SYSV) 164 : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) 165 { 166 switch (hash_type) { 167 case HashType::SYSV: 168 m_hash_function = &HashSection::calculate_elf_hash; 169 break; 170 case HashType::GNU: 171 m_hash_function = &HashSection::calculate_gnu_hash; 172 break; 173 default: 174 ASSERT_NOT_REACHED(); 175 break; 176 } 177 } 178 179 const Symbol lookup_symbol(const char*) const; 180 181 private: 182 u32 calculate_elf_hash(const char* name) const; 183 u32 calculate_gnu_hash(const char* name) const; 184 185 typedef u32 (HashSection::*HashFunction)(const char*) const; 186 HashFunction m_hash_function; 187 }; 188 189 unsigned symbol_count() const { return m_symbol_count; } 190 191 const Symbol symbol(unsigned) const; 192 const Symbol& the_undefined_symbol() const { return m_the_undefined_symbol; } 193 194 const Section init_section() const; 195 const Section fini_section() const; 196 const Section init_array_section() const; 197 const Section fini_array_section() const; 198 199 const HashSection hash_section() const; 200 201 const RelocationSection relocation_section() const; 202 const RelocationSection plt_relocation_section() const; 203 204 bool should_process_origin() const { return m_dt_flags & DF_ORIGIN; } 205 bool requires_symbolic_symbol_resolution() const { return m_dt_flags & DF_SYMBOLIC; } 206 // Text relocations meaning: we need to edit the .text section which is normally mapped PROT_READ 207 bool has_text_relocations() const { return m_dt_flags & DF_TEXTREL; } 208 bool must_bind_now() const { return m_dt_flags & DF_BIND_NOW; } 209 bool has_static_thread_local_storage() const { return m_dt_flags & DF_STATIC_TLS; } 210 211 VirtualAddress plt_got_base_address() const { return m_base_address.offset(m_procedure_linkage_table_offset); } 212 VirtualAddress base_address() const { return m_base_address; } 213 214private: 215 const char* symbol_string_table_string(Elf32_Word) const; 216 void parse(); 217 218 template<typename F> 219 void for_each_symbol(F) const; 220 221 template<typename F> 222 void for_each_dynamic_entry(F) const; 223 224 VirtualAddress m_base_address; 225 VirtualAddress m_dynamic_address; 226 Symbol m_the_undefined_symbol { *this, 0, {} }; 227 228 unsigned m_symbol_count { 0 }; 229 230 // Begin Section information collected from DT_* entries 231 FlatPtr m_init_offset { 0 }; 232 FlatPtr m_fini_offset { 0 }; 233 234 FlatPtr m_init_array_offset { 0 }; 235 size_t m_init_array_size { 0 }; 236 FlatPtr m_fini_array_offset { 0 }; 237 size_t m_fini_array_size { 0 }; 238 239 FlatPtr m_hash_table_offset { 0 }; 240 241 FlatPtr m_string_table_offset { 0 }; 242 size_t m_size_of_string_table { 0 }; 243 FlatPtr m_symbol_table_offset { 0 }; 244 size_t m_size_of_symbol_table_entry { 0 }; 245 246 Elf32_Sword m_procedure_linkage_table_relocation_type { -1 }; 247 FlatPtr m_plt_relocation_offset_location { 0 }; // offset of PLT relocations, at end of relocations 248 size_t m_size_of_plt_relocation_entry_list { 0 }; 249 FlatPtr m_procedure_linkage_table_offset { 0 }; 250 251 // NOTE: We'll only ever either RELA or REL entries, not both (thank god) 252 // NOTE: The x86 ABI will only ever genrerate REL entries. 253 size_t m_number_of_relocations { 0 }; 254 size_t m_size_of_relocation_entry { 0 }; 255 size_t m_size_of_relocation_table { 0 }; 256 FlatPtr m_relocation_table_offset { 0 }; 257 258 // DT_FLAGS 259 Elf32_Word m_dt_flags { 0 }; 260 // End Section information from DT_* entries 261}; 262 263template<typename F> 264inline void ELFDynamicObject::RelocationSection::for_each_relocation(F func) const 265{ 266 for (unsigned i = 0; i < relocation_count(); ++i) { 267 if (func(relocation(i)) == IterationDecision::Break) 268 break; 269 } 270} 271 272template<typename F> 273inline void ELFDynamicObject::for_each_symbol(F func) const 274{ 275 for (unsigned i = 0; i < symbol_count(); ++i) { 276 if (func(symbol(i)) == IterationDecision::Break) 277 break; 278 } 279} 280 281template<typename F> 282inline void ELFDynamicObject::for_each_dynamic_entry(F func) const 283{ 284 auto* dyns = reinterpret_cast<const Elf32_Dyn*>(m_dynamic_address.as_ptr()); 285 for (unsigned i = 0;; ++i) { 286 auto&& dyn = DynamicEntry(dyns[i]); 287 if (dyn.tag() == DT_NULL) 288 break; 289 if (func(dyn) == IterationDecision::Break) 290 break; 291 } 292}