Serenity Operating System
at master 696 lines 27 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) 2021, Andreas Kling <kling@serenityos.org> 5 * Copyright (c) 2022, Daniel Bertalan <dani@danielbertalan.dev> 6 * 7 * SPDX-License-Identifier: BSD-2-Clause 8 */ 9 10#include <AK/Optional.h> 11#include <AK/QuickSort.h> 12#include <AK/StringBuilder.h> 13#include <LibELF/DynamicLinker.h> 14#include <LibELF/DynamicLoader.h> 15#include <LibELF/Hashes.h> 16#include <LibELF/Validation.h> 17#include <assert.h> 18#include <bits/dlfcn_integration.h> 19#include <dlfcn.h> 20#include <errno.h> 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <sys/mman.h> 25#include <sys/stat.h> 26#include <unistd.h> 27 28#ifndef AK_OS_SERENITY 29static void* mmap_with_name(void* addr, size_t length, int prot, int flags, int fd, off_t offset, char const*) 30{ 31 return mmap(addr, length, prot, flags, fd, offset); 32} 33 34# define MAP_RANDOMIZED 0 35#endif 36 37namespace ELF { 38 39Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> DynamicLoader::try_create(int fd, DeprecatedString filepath) 40{ 41 VERIFY(filepath.starts_with('/')); 42 43 struct stat stat; 44 if (fstat(fd, &stat) < 0) { 45 return DlErrorMessage { "DynamicLoader::try_create fstat" }; 46 } 47 48 VERIFY(stat.st_size >= 0); 49 auto size = static_cast<size_t>(stat.st_size); 50 if (size < sizeof(ElfW(Ehdr))) 51 return DlErrorMessage { DeprecatedString::formatted("File {} has invalid ELF header", filepath) }; 52 53 DeprecatedString file_mmap_name = DeprecatedString::formatted("ELF_DYN: {}", filepath); 54 auto* data = mmap_with_name(nullptr, size, PROT_READ, MAP_SHARED, fd, 0, file_mmap_name.characters()); 55 if (data == MAP_FAILED) { 56 return DlErrorMessage { "DynamicLoader::try_create mmap" }; 57 } 58 59 auto loader = adopt_ref(*new DynamicLoader(fd, move(filepath), data, size)); 60 if (!loader->is_valid()) 61 return DlErrorMessage { "ELF image validation failed" }; 62 return loader; 63} 64 65DynamicLoader::DynamicLoader(int fd, DeprecatedString filepath, void* data, size_t size) 66 : m_filepath(move(filepath)) 67 , m_file_size(size) 68 , m_image_fd(fd) 69 , m_file_data(data) 70{ 71 m_elf_image = adopt_own(*new ELF::Image((u8*)m_file_data, m_file_size)); 72 m_valid = validate(); 73 if (m_valid) 74 find_tls_size_and_alignment(); 75 else 76 dbgln("Image validation failed for file {}", m_filepath); 77} 78 79DynamicLoader::~DynamicLoader() 80{ 81 if (munmap(m_file_data, m_file_size) < 0) { 82 perror("munmap"); 83 VERIFY_NOT_REACHED(); 84 } 85 if (close(m_image_fd) < 0) { 86 perror("close"); 87 VERIFY_NOT_REACHED(); 88 } 89} 90 91DynamicObject const& DynamicLoader::dynamic_object() const 92{ 93 if (!m_cached_dynamic_object) { 94 VirtualAddress dynamic_section_address; 95 96 image().for_each_program_header([&dynamic_section_address](auto program_header) { 97 if (program_header.type() == PT_DYNAMIC) { 98 dynamic_section_address = VirtualAddress(program_header.raw_data()); 99 } 100 }); 101 VERIFY(!dynamic_section_address.is_null()); 102 103 m_cached_dynamic_object = ELF::DynamicObject::create(m_filepath, VirtualAddress(image().base_address()), dynamic_section_address); 104 } 105 return *m_cached_dynamic_object; 106} 107 108void DynamicLoader::find_tls_size_and_alignment() 109{ 110 image().for_each_program_header([this](auto program_header) { 111 if (program_header.type() == PT_TLS) { 112 m_tls_size_of_current_object = program_header.size_in_memory(); 113 auto alignment = program_header.alignment(); 114 VERIFY(!alignment || is_power_of_two(alignment)); 115 m_tls_alignment_of_current_object = alignment > 1 ? alignment : 0; // No need to reserve extra space for single byte alignment 116 return IterationDecision::Break; 117 } 118 return IterationDecision::Continue; 119 }); 120} 121 122bool DynamicLoader::validate() 123{ 124 if (!image().is_valid()) 125 return false; 126 127 auto* elf_header = (ElfW(Ehdr)*)m_file_data; 128 if (!validate_elf_header(*elf_header, m_file_size)) 129 return false; 130 auto result_or_error = validate_program_headers(*elf_header, m_file_size, { m_file_data, m_file_size }); 131 if (result_or_error.is_error() || !result_or_error.value()) 132 return false; 133 return true; 134} 135 136RefPtr<DynamicObject> DynamicLoader::map() 137{ 138 if (m_dynamic_object) { 139 // Already mapped. 140 return nullptr; 141 } 142 143 if (!m_valid) { 144 dbgln("DynamicLoader::map failed: image is invalid"); 145 return nullptr; 146 } 147 148 load_program_headers(); 149 150 VERIFY(!m_base_address.is_null()); 151 152 m_dynamic_object = DynamicObject::create(m_filepath, m_base_address, m_dynamic_section_address); 153 m_dynamic_object->set_tls_offset(m_tls_offset); 154 m_dynamic_object->set_tls_size(m_tls_size_of_current_object); 155 156 return m_dynamic_object; 157} 158 159bool DynamicLoader::link(unsigned flags) 160{ 161 return load_stage_2(flags); 162} 163 164bool DynamicLoader::load_stage_2(unsigned flags) 165{ 166 VERIFY(flags & RTLD_GLOBAL); 167 168 if (m_dynamic_object->has_text_relocations()) { 169 dbgln("\033[33mWarning:\033[0m Dynamic object {} has text relocations", m_dynamic_object->filepath()); 170 for (auto& text_segment : m_text_segments) { 171 VERIFY(text_segment.address().get() != 0); 172 173#ifndef AK_OS_MACOS 174 // Remap this text region as private. 175 if (mremap(text_segment.address().as_ptr(), text_segment.size(), text_segment.size(), MAP_PRIVATE) == MAP_FAILED) { 176 perror("mremap .text: MAP_PRIVATE"); 177 return false; 178 } 179#endif 180 181 if (0 > mprotect(text_segment.address().as_ptr(), text_segment.size(), PROT_READ | PROT_WRITE)) { 182 perror("mprotect .text: PROT_READ | PROT_WRITE"); // FIXME: dlerror? 183 return false; 184 } 185 } 186 } else { 187 // .text needs to be executable while we process relocations because it might contain IFUNC resolvers. 188 // We don't allow IFUNC resolvers in objects with textrels. 189 for (auto& text_segment : m_text_segments) { 190 if (mprotect(text_segment.address().as_ptr(), text_segment.size(), PROT_READ | PROT_EXEC) < 0) { 191 perror("mprotect .text: PROT_READ | PROT_EXEC"); 192 return false; 193 } 194 } 195 } 196 do_main_relocations(); 197 return true; 198} 199 200void DynamicLoader::do_main_relocations() 201{ 202 auto do_single_relocation = [&](const ELF::DynamicObject::Relocation& relocation) { 203 switch (do_relocation(relocation, ShouldInitializeWeak::No)) { 204 case RelocationResult::Failed: 205 dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name()); 206 VERIFY_NOT_REACHED(); 207 case RelocationResult::ResolveLater: 208 m_unresolved_relocations.append(relocation); 209 break; 210 case RelocationResult::Success: 211 break; 212 } 213 }; 214 215 do_relr_relocations(); 216 m_dynamic_object->relocation_section().for_each_relocation(do_single_relocation); 217 m_dynamic_object->plt_relocation_section().for_each_relocation(do_single_relocation); 218} 219 220Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags) 221{ 222 do_lazy_relocations(); 223 if (flags & RTLD_LAZY) { 224 if (m_dynamic_object->has_plt()) 225 setup_plt_trampoline(); 226 } 227 228 if (m_dynamic_object->has_text_relocations()) { 229 // If we don't have textrels, .text has already been made executable by this point in load_stage_2. 230 for (auto& text_segment : m_text_segments) { 231 if (mprotect(text_segment.address().as_ptr(), text_segment.size(), PROT_READ | PROT_EXEC) < 0) { 232 return DlErrorMessage { DeprecatedString::formatted("mprotect .text: PROT_READ | PROT_EXEC: {}", strerror(errno)) }; 233 } 234 } 235 } 236 237 if (m_relro_segment_size) { 238 if (mprotect(m_relro_segment_address.as_ptr(), m_relro_segment_size, PROT_READ) < 0) { 239 return DlErrorMessage { DeprecatedString::formatted("mprotect .relro: PROT_READ: {}", strerror(errno)) }; 240 } 241 242#ifdef AK_OS_SERENITY 243 if (set_mmap_name(m_relro_segment_address.as_ptr(), m_relro_segment_size, DeprecatedString::formatted("{}: .relro", m_filepath).characters()) < 0) { 244 return DlErrorMessage { DeprecatedString::formatted("set_mmap_name .relro: {}", strerror(errno)) }; 245 } 246#endif 247 } 248 249 m_fully_relocated = true; 250 251 return NonnullRefPtr<DynamicObject> { *m_dynamic_object }; 252} 253 254void DynamicLoader::load_stage_4() 255{ 256 call_object_init_functions(); 257 258 m_fully_initialized = true; 259} 260 261void DynamicLoader::do_lazy_relocations() 262{ 263 for (auto const& relocation : m_unresolved_relocations) { 264 if (auto res = do_relocation(relocation, ShouldInitializeWeak::Yes); res != RelocationResult::Success) { 265 dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name()); 266 VERIFY_NOT_REACHED(); 267 } 268 } 269} 270 271void DynamicLoader::load_program_headers() 272{ 273 FlatPtr ph_load_start = SIZE_MAX; 274 FlatPtr ph_load_end = 0; 275 276 // We walk the program header list once to find the requested address ranges of the program. 277 // We don't fill in the list of regions yet to keep malloc memory blocks from interfering with our reservation. 278 image().for_each_program_header([&](Image::ProgramHeader const& program_header) { 279 if (program_header.type() != PT_LOAD) 280 return; 281 282 FlatPtr section_start = program_header.vaddr().get(); 283 FlatPtr section_end = section_start + program_header.size_in_memory(); 284 285 if (ph_load_start > section_start) 286 ph_load_start = section_start; 287 288 if (ph_load_end < section_end) 289 ph_load_end = section_end; 290 }); 291 292 void* requested_load_address = image().is_dynamic() ? nullptr : reinterpret_cast<void*>(ph_load_start); 293 294 int reservation_mmap_flags = MAP_ANON | MAP_PRIVATE | MAP_NORESERVE; 295 if (image().is_dynamic()) 296 reservation_mmap_flags |= MAP_RANDOMIZED; 297#ifdef MAP_FIXED_NOREPLACE 298 else 299 reservation_mmap_flags |= MAP_FIXED_NOREPLACE; 300#endif 301 302 // First, we make a dummy reservation mapping, in order to allocate enough VM 303 // to hold all regions contiguously in the address space. 304 305 FlatPtr ph_load_base = ph_load_start & ~(FlatPtr)0xfffu; 306 ph_load_end = round_up_to_power_of_two(ph_load_end, PAGE_SIZE); 307 308 size_t total_mapping_size = ph_load_end - ph_load_base; 309 310 // Before we make our reservation, unmap our existing mapped ELF image that we used for reading header information. 311 // This leaves our pointers dangling momentarily, but it reduces the chance that we will conflict with ourselves. 312 if (munmap(m_file_data, m_file_size) < 0) { 313 perror("munmap old mapping"); 314 VERIFY_NOT_REACHED(); 315 } 316 m_elf_image = nullptr; 317 m_file_data = nullptr; 318 319 auto* reservation = mmap(requested_load_address, total_mapping_size, PROT_NONE, reservation_mmap_flags, 0, 0); 320 if (reservation == MAP_FAILED) { 321 perror("mmap reservation"); 322 VERIFY_NOT_REACHED(); 323 } 324 325 // Now that we can't accidentally block our requested space, re-map our ELF image. 326 DeprecatedString file_mmap_name = DeprecatedString::formatted("ELF_DYN: {}", m_filepath); 327 auto* data = mmap_with_name(nullptr, m_file_size, PROT_READ, MAP_SHARED, m_image_fd, 0, file_mmap_name.characters()); 328 if (data == MAP_FAILED) { 329 perror("mmap new mapping"); 330 VERIFY_NOT_REACHED(); 331 } 332 333 m_file_data = data; 334 m_elf_image = adopt_own(*new ELF::Image((u8*)m_file_data, m_file_size)); 335 336 VERIFY(requested_load_address == nullptr || reservation == requested_load_address); 337 338 m_base_address = VirtualAddress { reservation }; 339 340 // Then we unmap the reservation. 341 if (munmap(reservation, total_mapping_size) < 0) { 342 perror("munmap reservation"); 343 VERIFY_NOT_REACHED(); 344 } 345 346 // Most binaries have four loadable regions, three of which are mapped 347 // (symbol tables/relocation information, executable instructions, read-only data) 348 // and one of which is copied (modifiable data). 349 // These are allocated in-line to cut down on the malloc calls. 350 Vector<ProgramHeaderRegion, 4> load_regions; 351 Vector<ProgramHeaderRegion, 3> map_regions; 352 Vector<ProgramHeaderRegion, 1> copy_regions; 353 Optional<ProgramHeaderRegion> relro_region; 354 355 VirtualAddress dynamic_region_desired_vaddr; 356 357 image().for_each_program_header([&](Image::ProgramHeader const& program_header) { 358 ProgramHeaderRegion region {}; 359 region.set_program_header(program_header.raw_header()); 360 if (region.is_tls_template()) { 361 // Skip, this is handled in DynamicLoader::copy_initial_tls_data_into. 362 } else if (region.is_load()) { 363 if (region.size_in_memory() == 0) 364 return; 365 load_regions.append(region); 366 if (region.is_writable()) { 367 copy_regions.append(region); 368 } else { 369 map_regions.append(region); 370 } 371 } else if (region.is_dynamic()) { 372 dynamic_region_desired_vaddr = region.desired_load_address(); 373 } else if (region.is_relro()) { 374 VERIFY(!relro_region.has_value()); 375 relro_region = region; 376 } 377 }); 378 379 VERIFY(!map_regions.is_empty() || !copy_regions.is_empty()); 380 381 auto compare_load_address = [](ProgramHeaderRegion& a, ProgramHeaderRegion& b) { 382 return a.desired_load_address().as_ptr() < b.desired_load_address().as_ptr(); 383 }; 384 385 quick_sort(load_regions, compare_load_address); 386 quick_sort(map_regions, compare_load_address); 387 quick_sort(copy_regions, compare_load_address); 388 389 // Process regions in order: .text, .data, .tls 390 for (auto& region : map_regions) { 391 FlatPtr ph_desired_base = region.desired_load_address().get(); 392 FlatPtr ph_base = region.desired_load_address().page_base().get(); 393 FlatPtr ph_end = ph_base + round_up_to_power_of_two(region.size_in_memory() + region.desired_load_address().get() - ph_base, PAGE_SIZE); 394 395 StringBuilder builder; 396 builder.append(m_filepath); 397 if (region.is_executable()) 398 builder.append(": .text"sv); 399 else 400 builder.append(": .rodata"sv); 401 402 // Now we can map the text segment at the reserved address. 403 auto* segment_base = (u8*)mmap_with_name( 404 (u8*)reservation + ph_base - ph_load_base, 405 ph_desired_base - ph_base + region.size_in_image(), 406 PROT_READ, 407 MAP_FILE | MAP_SHARED | MAP_FIXED, 408 m_image_fd, 409 VirtualAddress { region.offset() }.page_base().get(), 410 builder.to_deprecated_string().characters()); 411 412 if (segment_base == MAP_FAILED) { 413 perror("mmap non-writable"); 414 VERIFY_NOT_REACHED(); 415 } 416 417 if (region.is_executable()) 418 m_text_segments.append({ VirtualAddress { segment_base }, ph_end - ph_base }); 419 } 420 421 VERIFY(requested_load_address == nullptr || requested_load_address == reservation); 422 423 if (relro_region.has_value()) { 424 m_relro_segment_size = relro_region->size_in_memory(); 425 m_relro_segment_address = VirtualAddress { (u8*)reservation + relro_region->desired_load_address().get() - ph_load_base }; 426 } 427 428 if (image().is_dynamic()) 429 m_dynamic_section_address = VirtualAddress { (u8*)reservation + dynamic_region_desired_vaddr.get() - ph_load_base }; 430 else 431 m_dynamic_section_address = dynamic_region_desired_vaddr; 432 433 for (auto& region : copy_regions) { 434 FlatPtr ph_data_base = region.desired_load_address().page_base().get(); 435 FlatPtr ph_data_end = ph_data_base + round_up_to_power_of_two(region.size_in_memory() + region.desired_load_address().get() - ph_data_base, PAGE_SIZE); 436 437 auto* data_segment_address = (u8*)reservation + ph_data_base - ph_load_base; 438 size_t data_segment_size = ph_data_end - ph_data_base; 439 440 // Finally, we make an anonymous mapping for the data segment. Contents are then copied from the file. 441 auto* data_segment = (u8*)mmap_with_name( 442 data_segment_address, 443 data_segment_size, 444 PROT_READ | PROT_WRITE, 445 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 446 0, 447 0, 448 DeprecatedString::formatted("{}: .data", m_filepath).characters()); 449 450 if (MAP_FAILED == data_segment) { 451 perror("mmap writable"); 452 VERIFY_NOT_REACHED(); 453 } 454 455 VirtualAddress data_segment_start; 456 if (image().is_dynamic()) 457 data_segment_start = VirtualAddress { (u8*)reservation + region.desired_load_address().get() }; 458 else 459 data_segment_start = region.desired_load_address(); 460 461 VERIFY(data_segment_start.as_ptr() + region.size_in_memory() <= data_segment + data_segment_size); 462 463 memcpy(data_segment_start.as_ptr(), (u8*)m_file_data + region.offset(), region.size_in_image()); 464 } 465} 466 467DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicObject::Relocation& relocation, ShouldInitializeWeak should_initialize_weak) 468{ 469 FlatPtr* patch_ptr = nullptr; 470 if (is_dynamic()) 471 patch_ptr = (FlatPtr*)(m_dynamic_object->base_address().as_ptr() + relocation.offset()); 472 else 473 patch_ptr = (FlatPtr*)(FlatPtr)relocation.offset(); 474 475 auto call_ifunc_resolver = [](VirtualAddress address) { 476 return VirtualAddress { reinterpret_cast<DynamicObject::IfuncResolver>(address.get())() }; 477 }; 478 479 switch (relocation.type()) { 480 481 case R_X86_64_NONE: 482 // Apparently most loaders will just skip these? 483 // Seems if the 'link editor' generates one something is funky with your code 484 break; 485 case R_AARCH64_ABS64: 486 case R_X86_64_64: { 487 auto symbol = relocation.symbol(); 488 auto res = lookup_symbol(symbol); 489 if (!res.has_value()) { 490 if (symbol.bind() == STB_WEAK) 491 return RelocationResult::ResolveLater; 492 dbgln("ERROR: symbol not found: {}.", symbol.name()); 493 return RelocationResult::Failed; 494 } 495 auto symbol_address = res.value().address; 496 if (relocation.addend_used()) 497 *patch_ptr = symbol_address.get() + relocation.addend(); 498 else 499 *patch_ptr += symbol_address.get(); 500 if (res.value().type == STT_GNU_IFUNC) 501 *patch_ptr = call_ifunc_resolver(VirtualAddress { *patch_ptr }).get(); 502 break; 503 } 504 case R_AARCH64_GLOB_DAT: 505 case R_X86_64_GLOB_DAT: { 506 auto symbol = relocation.symbol(); 507 auto res = lookup_symbol(symbol); 508 VirtualAddress symbol_location; 509 if (!res.has_value()) { 510 if (symbol.bind() == STB_WEAK) { 511 if (should_initialize_weak == ShouldInitializeWeak::No) 512 return RelocationResult::ResolveLater; 513 } else { 514 // Symbol not found 515 return RelocationResult::Failed; 516 } 517 518 symbol_location = VirtualAddress { (FlatPtr)0 }; 519 } else { 520 symbol_location = res.value().address; 521 if (res.value().type == STT_GNU_IFUNC) { 522 if (res.value().dynamic_object != nullptr && res.value().dynamic_object->has_text_relocations()) { 523 dbgln("\033[31mError:\033[0m Refusing to call IFUNC resolver defined in an object with text relocations."); 524 return RelocationResult::Failed; 525 } 526 symbol_location = call_ifunc_resolver(symbol_location); 527 } 528 } 529 VERIFY(symbol_location != m_dynamic_object->base_address()); 530 *patch_ptr = symbol_location.get(); 531 break; 532 } 533 case R_AARCH64_RELATIVE: 534 case R_X86_64_RELATIVE: { 535 if (!image().is_dynamic()) 536 break; 537 // FIXME: According to the spec, R_386_relative ones must be done first. 538 // We could explicitly do them first using m_number_of_relocations from DT_RELCOUNT 539 // However, our compiler is nice enough to put them at the front of the relocations for us :) 540 if (relocation.addend_used()) 541 *patch_ptr = m_dynamic_object->base_address().offset(relocation.addend()).get(); 542 else 543 *patch_ptr += m_dynamic_object->base_address().get(); 544 break; 545 } 546 case R_AARCH64_TLS_TPREL64: 547 case R_X86_64_TPOFF64: { 548 auto symbol = relocation.symbol(); 549 FlatPtr symbol_value; 550 DynamicObject const* dynamic_object_of_symbol; 551 if (relocation.symbol_index() != 0) { 552 auto res = lookup_symbol(symbol); 553 if (!res.has_value()) 554 break; 555 VERIFY(symbol.type() != STT_GNU_IFUNC); 556 symbol_value = res.value().value; 557 dynamic_object_of_symbol = res.value().dynamic_object; 558 } else { 559 symbol_value = 0; 560 dynamic_object_of_symbol = &relocation.dynamic_object(); 561 } 562 VERIFY(dynamic_object_of_symbol); 563 size_t addend = relocation.addend_used() ? relocation.addend() : *patch_ptr; 564 565 *patch_ptr = addend + dynamic_object_of_symbol->tls_offset().value() + symbol_value; 566 567 // At offset 0 there's the thread's ThreadSpecificData structure, we don't want to collide with it. 568 VERIFY(static_cast<ssize_t>(*patch_ptr) < 0); 569 570 break; 571 } 572 case R_AARCH64_JUMP_SLOT: 573 case R_X86_64_JUMP_SLOT: { 574 // FIXME: Or BIND_NOW flag passed in? 575 if (m_dynamic_object->must_bind_now()) { 576 // Eagerly BIND_NOW the PLT entries, doing all the symbol looking goodness 577 // The patch method returns the address for the LAZY fixup path, but we don't need it here 578 m_dynamic_object->patch_plt_entry(relocation.offset_in_section()); 579 } else { 580 auto relocation_address = (FlatPtr*)relocation.address().as_ptr(); 581 582 if (image().is_dynamic()) 583 *relocation_address += m_dynamic_object->base_address().get(); 584 } 585 break; 586 } 587 case R_X86_64_IRELATIVE: { 588 VirtualAddress resolver; 589 if (relocation.addend_used()) 590 resolver = m_dynamic_object->base_address().offset(relocation.addend()); 591 else 592 resolver = m_dynamic_object->base_address().offset(*patch_ptr); 593 594 if (m_dynamic_object->has_text_relocations()) { 595 dbgln("\033[31mError:\033[0m Refusing to call IFUNC resolver defined in an object with text relocations."); 596 return RelocationResult::Failed; 597 } 598 599 *patch_ptr = call_ifunc_resolver(resolver).get(); 600 break; 601 } 602 default: 603 // Raise the alarm! Someone needs to implement this relocation type 604 dbgln("Found a new exciting relocation type {}", relocation.type()); 605 VERIFY_NOT_REACHED(); 606 } 607 return RelocationResult::Success; 608} 609 610void DynamicLoader::do_relr_relocations() 611{ 612 auto base_address = m_dynamic_object->base_address().get(); 613 m_dynamic_object->for_each_relr_relocation([base_address](FlatPtr address) { 614 *(FlatPtr*)address += base_address; 615 }); 616} 617 618void DynamicLoader::copy_initial_tls_data_into(ByteBuffer& buffer) const 619{ 620 image().for_each_program_header([this, &buffer](ELF::Image::ProgramHeader program_header) { 621 if (program_header.type() != PT_TLS) 622 return IterationDecision::Continue; 623 624 // Note: The "size in image" is only concerned with initialized data. Uninitialized data (.tbss) is 625 // only included in the "size in memory" metric, and is expected to not be touched or read from, as 626 // it is not present in the image and zeroed out in-memory. We will still check that the buffer has 627 // space for both the initialized and the uninitialized data. 628 // Note: The m_tls_offset here is (of course) negative. 629 // TODO: Is the initialized data always in the beginning of the TLS segment, or should we walk the 630 // sections to figure that out? 631 size_t tls_start_in_buffer = buffer.size() + m_tls_offset; 632 VERIFY(program_header.size_in_image() <= program_header.size_in_memory()); 633 VERIFY(program_header.size_in_memory() <= m_tls_size_of_current_object); 634 VERIFY(tls_start_in_buffer + program_header.size_in_memory() <= buffer.size()); 635 memcpy(buffer.data() + tls_start_in_buffer, static_cast<const u8*>(m_file_data) + program_header.offset(), program_header.size_in_image()); 636 637 return IterationDecision::Break; 638 }); 639} 640 641// Defined in <arch>/plt_trampoline.S 642extern "C" void _plt_trampoline(void) __attribute__((visibility("hidden"))); 643 644void DynamicLoader::setup_plt_trampoline() 645{ 646 VERIFY(m_dynamic_object); 647 VERIFY(m_dynamic_object->has_plt()); 648 VirtualAddress got_address = m_dynamic_object->plt_got_base_address(); 649 650 auto* got_ptr = (FlatPtr*)got_address.as_ptr(); 651 got_ptr[1] = (FlatPtr)m_dynamic_object.ptr(); 652 got_ptr[2] = (FlatPtr)&_plt_trampoline; 653} 654 655// Called from our ASM routine _plt_trampoline. 656// Tell the compiler that it might be called from other places: 657extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset); 658extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset) 659{ 660 return object->patch_plt_entry(relocation_offset).get(); 661} 662 663void DynamicLoader::call_object_init_functions() 664{ 665 typedef void (*InitFunc)(); 666 667 if (m_dynamic_object->has_init_section()) { 668 auto init_function = (InitFunc)(m_dynamic_object->init_section().address().as_ptr()); 669 (init_function)(); 670 } 671 672 if (m_dynamic_object->has_init_array_section()) { 673 auto init_array_section = m_dynamic_object->init_array_section(); 674 675 InitFunc* init_begin = (InitFunc*)(init_array_section.address().as_ptr()); 676 InitFunc* init_end = init_begin + init_array_section.entry_count(); 677 while (init_begin != init_end) { 678 // Android sources claim that these can be -1, to be ignored. 679 // 0 definitely shows up. Apparently 0/-1 are valid? Confusing. 680 if (!*init_begin || ((FlatPtr)*init_begin == (FlatPtr)-1)) 681 continue; 682 (*init_begin)(); 683 ++init_begin; 684 } 685 } 686} 687 688Optional<DynamicObject::SymbolLookupResult> DynamicLoader::lookup_symbol(const ELF::DynamicObject::Symbol& symbol) 689{ 690 if (symbol.is_undefined() || symbol.bind() == STB_WEAK) 691 return DynamicLinker::lookup_global_symbol(symbol.name()); 692 693 return DynamicObject::SymbolLookupResult { symbol.value(), symbol.size(), symbol.address(), symbol.bind(), symbol.type(), &symbol.object() }; 694} 695 696} // end namespace ELF