Serenity Operating System
at master 491 lines 16 kB view raw
1/* 2 * Copyright (c) 2019-2020, Andrew Kaster <akaster@serenityos.org> 3 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> 4 * Copyright (c) 2022, the SerenityOS developers. 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#pragma once 10 11#include <AK/Assertions.h> 12#include <AK/Concepts.h> 13#include <AK/DeprecatedString.h> 14#include <AK/RefCounted.h> 15#include <Kernel/VirtualAddress.h> 16#include <LibC/elf.h> 17#include <LibC/link.h> 18 19namespace ELF { 20 21class DynamicObject : public RefCounted<DynamicObject> { 22public: 23 static NonnullRefPtr<DynamicObject> create(DeprecatedString const& filepath, VirtualAddress base_address, VirtualAddress dynamic_section_address); 24 static char const* name_for_dtag(ElfW(Sword) d_tag); 25 26 ~DynamicObject(); 27 void dump() const; 28 29 class DynamicEntry; 30 class Section; 31 class RelocationSection; 32 class Symbol; 33 class Relocation; 34 class HashSection; 35 36 class DynamicEntry { 37 public: 38 explicit DynamicEntry(const ElfW(Dyn) & dyn) 39 : m_dyn(dyn) 40 { 41 } 42 43 ~DynamicEntry() = default; 44 45 ElfW(Sword) tag() const { return m_dyn.d_tag; } 46 ElfW(Addr) ptr() const { return m_dyn.d_un.d_ptr; } 47 ElfW(Word) val() const { return m_dyn.d_un.d_val; } 48 49 private: 50 const ElfW(Dyn) & m_dyn; 51 }; 52 53 class Symbol { 54 public: 55 Symbol(DynamicObject const& dynamic, unsigned index, const ElfW(Sym) & sym) 56 : m_dynamic(dynamic) 57 , m_sym(sym) 58 , m_index(index) 59 { 60 } 61 62 StringView name() const { return m_dynamic.symbol_string_table_string(m_sym.st_name); } 63 char const* raw_name() const { return m_dynamic.raw_symbol_string_table_string(m_sym.st_name); } 64 unsigned section_index() const { return m_sym.st_shndx; } 65 FlatPtr value() const { return m_sym.st_value; } 66 size_t size() const { return m_sym.st_size; } 67 unsigned index() const { return m_index; } 68 unsigned type() const 69 { 70 return ELF64_ST_TYPE(m_sym.st_info); 71 } 72 unsigned bind() const { return ELF64_ST_BIND(m_sym.st_info); } 73 74 bool is_undefined() const 75 { 76 return section_index() == 0; 77 } 78 79 VirtualAddress address() const 80 { 81 if (m_dynamic.elf_is_dynamic()) 82 return m_dynamic.base_address().offset(value()); 83 return VirtualAddress { value() }; 84 } 85 DynamicObject const& object() const { return m_dynamic; } 86 87 private: 88 DynamicObject const& m_dynamic; 89 const ElfW(Sym) & m_sym; 90 unsigned const m_index; 91 }; 92 93 class Section { 94 public: 95 Section(DynamicObject const& dynamic, unsigned section_offset, unsigned section_size_bytes, unsigned entry_size, StringView name) 96 : m_dynamic(dynamic) 97 , m_section_offset(section_offset) 98 , m_section_size_bytes(section_size_bytes) 99 , m_entry_size(entry_size) 100 , m_name(name) 101 { 102 } 103 ~Section() = default; 104 105 StringView name() const { return m_name; } 106 unsigned offset() const { return m_section_offset; } 107 unsigned size() const { return m_section_size_bytes; } 108 unsigned entry_size() const { return m_entry_size; } 109 unsigned entry_count() const 110 { 111 return !entry_size() ? 0 : size() / entry_size(); 112 } 113 VirtualAddress address() const 114 { 115 return m_dynamic.base_address().offset(m_section_offset); 116 } 117 118 protected: 119 friend class RelocationSection; 120 friend class HashSection; 121 DynamicObject const& m_dynamic; 122 unsigned m_section_offset; 123 unsigned m_section_size_bytes; 124 unsigned m_entry_size; 125 StringView m_name; 126 }; 127 128 class RelocationSection : public Section { 129 public: 130 explicit RelocationSection(Section const& section, bool addend_used) 131 : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) 132 , m_addend_used(addend_used) 133 { 134 } 135 unsigned relocation_count() const { return entry_count(); } 136 Relocation relocation(unsigned index) const; 137 Relocation relocation_at_offset(unsigned offset) const; 138 139 template<IteratorFunction<DynamicObject::Relocation&> F> 140 void for_each_relocation(F) const; 141 template<VoidFunction<DynamicObject::Relocation&> F> 142 void for_each_relocation(F func) const; 143 144 private: 145 bool const m_addend_used; 146 }; 147 148 class Relocation { 149 public: 150 Relocation(DynamicObject const& dynamic, const ElfW(Rela) & rel, unsigned offset_in_section, bool addend_used) 151 : m_dynamic(dynamic) 152 , m_rel(rel) 153 , m_offset_in_section(offset_in_section) 154 , m_addend_used(addend_used) 155 { 156 } 157 158 ~Relocation() = default; 159 160 unsigned offset_in_section() const { return m_offset_in_section; } 161 unsigned offset() const { return m_rel.r_offset; } 162 unsigned type() const 163 { 164 return ELF64_R_TYPE(m_rel.r_info); 165 } 166 unsigned symbol_index() const { return ELF64_R_SYM(m_rel.r_info); } 167 unsigned addend() const 168 { 169 VERIFY(m_addend_used); 170 return m_rel.r_addend; 171 } 172 bool addend_used() const { return m_addend_used; } 173 174 Symbol symbol() const 175 { 176 return m_dynamic.symbol(symbol_index()); 177 } 178 VirtualAddress address() const 179 { 180 if (m_dynamic.elf_is_dynamic()) 181 return m_dynamic.base_address().offset(offset()); 182 return VirtualAddress { offset() }; 183 } 184 [[nodiscard]] DynamicObject const& dynamic_object() const { return m_dynamic; } 185 186 private: 187 DynamicObject const& m_dynamic; 188 const ElfW(Rela) & m_rel; 189 unsigned const m_offset_in_section; 190 bool const m_addend_used; 191 }; 192 193 enum class HashType { 194 SYSV, 195 GNU 196 }; 197 198 class HashSymbol { 199 public: 200 HashSymbol(StringView name) 201 : m_name(name) 202 { 203 } 204 205 StringView name() const { return m_name; } 206 u32 gnu_hash() const; 207 u32 sysv_hash() const; 208 209 private: 210 StringView m_name; 211 mutable Optional<u32> m_gnu_hash; 212 mutable Optional<u32> m_sysv_hash; 213 }; 214 215 class HashSection : public Section { 216 public: 217 HashSection(Section const& section, HashType hash_type) 218 : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) 219 , m_hash_type(hash_type) 220 { 221 } 222 223 Optional<Symbol> lookup_symbol(HashSymbol const& symbol) const 224 { 225 if (m_hash_type == HashType::SYSV) 226 return lookup_sysv_symbol(symbol.name(), symbol.sysv_hash()); 227 return lookup_gnu_symbol(symbol.name(), symbol.gnu_hash()); 228 } 229 230 private: 231 Optional<Symbol> lookup_sysv_symbol(StringView name, u32 hash_value) const; 232 Optional<Symbol> lookup_gnu_symbol(StringView name, u32 hash) const; 233 234 HashType m_hash_type {}; 235 }; 236 237 unsigned symbol_count() const { return m_symbol_count; } 238 239 Symbol symbol(unsigned) const; 240 241 typedef void (*InitializationFunction)(); 242 typedef ElfW(Addr) (*IfuncResolver)(); 243 244 bool has_init_section() const { return m_init_offset != 0; } 245 bool has_init_array_section() const { return m_init_array_offset != 0; } 246 Section init_section() const; 247 InitializationFunction init_section_function() const; 248 Section fini_section() const; 249 Section init_array_section() const; 250 Section fini_array_section() const; 251 252 HashSection hash_section() const 253 { 254 auto section_name = m_hash_type == HashType::SYSV ? "DT_HASH"sv : "DT_GNU_HASH"sv; 255 256 return HashSection(Section(*this, m_hash_table_offset, 0, 0, section_name), m_hash_type); 257 } 258 259 RelocationSection relocation_section() const; 260 RelocationSection plt_relocation_section() const; 261 Section relr_relocation_section() const; 262 263 bool should_process_origin() const { return m_dt_flags & DF_ORIGIN; } 264 bool requires_symbolic_symbol_resolution() const { return m_dt_flags & DF_SYMBOLIC; } 265 // Text relocations meaning: we need to edit the .text section which is normally mapped PROT_READ 266 bool has_text_relocations() const { return m_dt_flags & DF_TEXTREL; } 267 bool must_bind_now() const { return m_dt_flags & DF_BIND_NOW; } 268 bool has_static_thread_local_storage() const { return m_dt_flags & DF_STATIC_TLS; } 269 270 bool has_plt() const { return m_procedure_linkage_table_offset.has_value(); } 271 VirtualAddress plt_got_base_address() const { return m_base_address.offset(m_procedure_linkage_table_offset.value()); } 272 VirtualAddress base_address() const { return m_base_address; } 273 274 DeprecatedString const& filepath() const { return m_filepath; } 275 276 StringView rpath() const { return m_has_rpath ? symbol_string_table_string(m_rpath_index) : StringView {}; } 277 StringView runpath() const { return m_has_runpath ? symbol_string_table_string(m_runpath_index) : StringView {}; } 278 StringView soname() const { return m_has_soname ? symbol_string_table_string(m_soname_index) : StringView {}; } 279 280 Optional<FlatPtr> tls_offset() const { return m_tls_offset; } 281 Optional<FlatPtr> tls_size() const { return m_tls_size; } 282 void set_tls_offset(FlatPtr offset) { m_tls_offset = offset; } 283 void set_tls_size(FlatPtr size) { m_tls_size = size; } 284 285 ElfW(Half) program_header_count() const; 286 const ElfW(Phdr) * program_headers() const; 287 288 template<VoidFunction<StringView> F> 289 void for_each_needed_library(F) const; 290 291 template<VoidFunction<InitializationFunction&> F> 292 void for_each_initialization_array_function(F f) const; 293 294 template<IteratorFunction<DynamicEntry&> F> 295 void for_each_dynamic_entry(F) const; 296 template<VoidFunction<DynamicEntry&> F> 297 void for_each_dynamic_entry(F func) const; 298 299 template<VoidFunction<Symbol&> F> 300 void for_each_symbol(F) const; 301 302 template<typename F> 303 void for_each_relr_relocation(F) const; 304 305 struct SymbolLookupResult { 306 FlatPtr value { 0 }; 307 size_t size { 0 }; 308 VirtualAddress address; 309 unsigned bind { STB_LOCAL }; 310 unsigned type { STT_FUNC }; 311 const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined 312 }; 313 314 Optional<SymbolLookupResult> lookup_symbol(StringView name) const; 315 Optional<SymbolLookupResult> lookup_symbol(HashSymbol const& symbol) const; 316 317 // Will be called from _fixup_plt_entry, as part of the PLT trampoline 318 VirtualAddress patch_plt_entry(u32 relocation_offset); 319 320 bool elf_is_dynamic() const { return m_is_elf_dynamic; } 321 322 void* symbol_for_name(StringView name); 323 324private: 325 explicit DynamicObject(DeprecatedString const& filepath, VirtualAddress base_address, VirtualAddress dynamic_section_address); 326 327 StringView symbol_string_table_string(ElfW(Word)) const; 328 char const* raw_symbol_string_table_string(ElfW(Word)) const; 329 void parse(); 330 331 DeprecatedString m_filepath; 332 333 VirtualAddress m_base_address; 334 VirtualAddress m_dynamic_address; 335 VirtualAddress m_elf_base_address; 336 337 unsigned m_symbol_count { 0 }; 338 339 // Begin Section information collected from DT_* entries 340 FlatPtr m_init_offset { 0 }; 341 FlatPtr m_fini_offset { 0 }; 342 343 FlatPtr m_init_array_offset { 0 }; 344 size_t m_init_array_size { 0 }; 345 FlatPtr m_fini_array_offset { 0 }; 346 size_t m_fini_array_size { 0 }; 347 348 FlatPtr m_hash_table_offset { 0 }; 349 HashType m_hash_type { HashType::SYSV }; 350 351 FlatPtr m_string_table_offset { 0 }; 352 size_t m_size_of_string_table { 0 }; 353 FlatPtr m_symbol_table_offset { 0 }; 354 size_t m_size_of_symbol_table_entry { 0 }; 355 356 ElfW(Sword) m_procedure_linkage_table_relocation_type { -1 }; 357 FlatPtr m_plt_relocation_offset_location { 0 }; // offset of PLT relocations, at end of relocations 358 size_t m_size_of_plt_relocation_entry_list { 0 }; 359 Optional<FlatPtr> m_procedure_linkage_table_offset; 360 361 // NOTE: We'll only ever either RELA or REL entries, not both (thank god) 362 // NOTE: The x86 ABI will only ever genrerate REL entries. 363 size_t m_number_of_relocations { 0 }; 364 size_t m_size_of_relocation_entry { 0 }; 365 size_t m_size_of_relocation_table { 0 }; 366 bool m_addend_used { false }; 367 FlatPtr m_relocation_table_offset { 0 }; 368 size_t m_size_of_relr_relocations_entry { 0 }; 369 size_t m_size_of_relr_relocation_table { 0 }; 370 FlatPtr m_relr_relocation_table_offset { 0 }; 371 bool m_is_elf_dynamic { false }; 372 373 // DT_FLAGS 374 ElfW(Word) m_dt_flags { 0 }; 375 376 bool m_has_soname { false }; 377 ElfW(Word) m_soname_index { 0 }; // Index into dynstr table for SONAME 378 bool m_has_rpath { false }; 379 ElfW(Word) m_rpath_index { 0 }; // Index into dynstr table for RPATH 380 bool m_has_runpath { false }; 381 ElfW(Word) m_runpath_index { 0 }; // Index into dynstr table for RUNPATH 382 383 Optional<FlatPtr> m_tls_offset; 384 Optional<FlatPtr> m_tls_size; 385 // End Section information from DT_* entries 386}; 387 388template<IteratorFunction<DynamicObject::Relocation&> F> 389inline void DynamicObject::RelocationSection::for_each_relocation(F func) const 390{ 391 for (unsigned i = 0; i < relocation_count(); ++i) { 392 auto const reloc = relocation(i); 393 if (reloc.type() == 0) 394 continue; 395 if (func(reloc) == IterationDecision::Break) 396 break; 397 } 398} 399 400template<VoidFunction<DynamicObject::Relocation&> F> 401inline void DynamicObject::RelocationSection::for_each_relocation(F func) const 402{ 403 for_each_relocation([&](auto& reloc) { 404 func(reloc); 405 return IterationDecision::Continue; 406 }); 407} 408 409template<typename F> 410inline void DynamicObject::for_each_relr_relocation(F f) const 411{ 412 auto section = relr_relocation_section(); 413 if (section.entry_count() == 0) 414 return; 415 416 VERIFY(section.entry_size() == sizeof(FlatPtr)); 417 VERIFY(section.size() >= section.entry_size() * section.entry_count()); 418 419 auto* entries = reinterpret_cast<ElfW(Relr)*>(section.address().get()); 420 auto base = base_address().get(); 421 FlatPtr patch_addr = 0; 422 for (unsigned i = 0; i < section.entry_count(); ++i) { 423 if ((entries[i] & 1u) == 0) { 424 patch_addr = base + entries[i]; 425 f(patch_addr); 426 patch_addr += sizeof(FlatPtr); 427 } else { 428 unsigned j = 0; 429 for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j) 430 if (bitmap & 1u) 431 f(patch_addr + j * sizeof(FlatPtr)); 432 433 patch_addr += (8 * sizeof(FlatPtr) - 1) * sizeof(FlatPtr); 434 } 435 } 436} 437 438template<VoidFunction<DynamicObject::Symbol&> F> 439inline void DynamicObject::for_each_symbol(F func) const 440{ 441 for (unsigned i = 0; i < symbol_count(); ++i) { 442 func(symbol(i)); 443 } 444} 445 446template<IteratorFunction<DynamicObject::DynamicEntry&> F> 447inline void DynamicObject::for_each_dynamic_entry(F func) const 448{ 449 auto* dyns = reinterpret_cast<const ElfW(Dyn)*>(m_dynamic_address.as_ptr()); 450 for (unsigned i = 0;; ++i) { 451 auto&& dyn = DynamicEntry(dyns[i]); 452 if (dyn.tag() == DT_NULL) 453 break; 454 if (func(dyn) == IterationDecision::Break) 455 break; 456 } 457} 458 459template<VoidFunction<DynamicObject::DynamicEntry&> F> 460inline void DynamicObject::for_each_dynamic_entry(F func) const 461{ 462 for_each_dynamic_entry([&](auto& dyn) { 463 func(dyn); 464 return IterationDecision::Continue; 465 }); 466} 467 468template<VoidFunction<StringView> F> 469inline void DynamicObject::for_each_needed_library(F func) const 470{ 471 for_each_dynamic_entry([func, this](auto entry) { 472 if (entry.tag() != DT_NEEDED) 473 return; 474 ElfW(Word) offset = entry.val(); 475 func(symbol_string_table_string(offset)); 476 }); 477} 478 479template<VoidFunction<DynamicObject::InitializationFunction&> F> 480void DynamicObject::for_each_initialization_array_function(F f) const 481{ 482 if (!has_init_array_section()) 483 return; 484 FlatPtr init_array = (FlatPtr)init_array_section().address().as_ptr(); 485 for (size_t i = 0; i < (m_init_array_size / sizeof(void*)); ++i) { 486 InitializationFunction current = ((InitializationFunction*)(init_array))[i]; 487 f(current); 488 } 489} 490 491} // end namespace ELF