Serenity Operating System
at master 100 lines 3.9 kB view raw
1/* 2 * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibC/elf.h> 8#include <LibELF/Relocation.h> 9 10namespace ELF { 11 12bool perform_relative_relocations(FlatPtr base_address) 13{ 14 15 ElfW(Ehdr)* header = (ElfW(Ehdr)*)(base_address); 16 ElfW(Phdr)* pheader = (ElfW(Phdr)*)(base_address + header->e_phoff); 17 FlatPtr dynamic_section_addr = 0; 18 for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) { 19 if (pheader->p_type != PT_DYNAMIC) 20 continue; 21 dynamic_section_addr = pheader->p_vaddr + base_address; 22 } 23 if (!dynamic_section_addr) 24 return false; 25 26 FlatPtr relocation_section_addr = 0; 27 size_t relocation_table_size = 0; 28 size_t relocation_count = 0; 29 size_t relocation_entry_size = 0; 30 FlatPtr relr_relocation_section_addr = 0; 31 size_t relr_relocation_table_size = 0; 32 bool use_addend = false; 33 auto* dyns = reinterpret_cast<const ElfW(Dyn)*>(dynamic_section_addr); 34 for (unsigned i = 0;; ++i) { 35 auto& dyn = dyns[i]; 36 if (dyn.d_tag == DT_NULL) 37 break; 38 if (dyn.d_tag == DT_RELA) 39 use_addend = true; 40 if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELA) 41 relocation_section_addr = base_address + dyn.d_un.d_ptr; 42 else if (dyn.d_tag == DT_RELCOUNT || dyn.d_tag == DT_RELACOUNT) 43 relocation_count = dyn.d_un.d_val; 44 else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) 45 relocation_table_size = dyn.d_un.d_val; 46 else if (dyn.d_tag == DT_RELENT || dyn.d_tag == DT_RELAENT) 47 relocation_entry_size = dyn.d_un.d_val; 48 else if (dyn.d_tag == DT_RELR) 49 relr_relocation_section_addr = base_address + dyn.d_un.d_ptr; 50 else if (dyn.d_tag == DT_RELRSZ) 51 relr_relocation_table_size = dyn.d_un.d_val; 52 else if (dyn.d_tag == DT_RELRENT) 53 VERIFY(dyn.d_un.d_val == sizeof(FlatPtr)); 54 } 55 56 if ((!relocation_section_addr || !relocation_table_size || !relocation_count) && (!relr_relocation_section_addr || !relr_relocation_table_size)) 57 return false; 58 59 for (unsigned i = 0; i < relocation_count; ++i) { 60 size_t offset_in_section = i * relocation_entry_size; 61 auto* relocation = (ElfW(Rela)*)(relocation_section_addr + offset_in_section); 62 VERIFY(ELF64_R_TYPE(relocation->r_info) == R_X86_64_RELATIVE || ELF64_R_TYPE(relocation->r_info) == R_AARCH64_RELATIVE); 63 auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset); 64 FlatPtr relocated_address; 65 if (use_addend) { 66 relocated_address = base_address + relocation->r_addend; 67 } else { 68 __builtin_memcpy(&relocated_address, patch_address, sizeof(relocated_address)); 69 relocated_address += base_address; 70 } 71 __builtin_memcpy(patch_address, &relocated_address, sizeof(relocated_address)); 72 } 73 74 auto patch_relr = [base_address](FlatPtr* patch_ptr) { 75 FlatPtr relocated_address; 76 __builtin_memcpy(&relocated_address, patch_ptr, sizeof(FlatPtr)); 77 relocated_address += base_address; 78 __builtin_memcpy(patch_ptr, &relocated_address, sizeof(FlatPtr)); 79 }; 80 81 auto* entries = reinterpret_cast<ElfW(Relr)*>(relr_relocation_section_addr); 82 FlatPtr* patch_ptr = nullptr; 83 84 for (unsigned i = 0; i < relr_relocation_table_size / sizeof(FlatPtr); ++i) { 85 if ((entries[i] & 1u) == 0) { 86 patch_ptr = reinterpret_cast<FlatPtr*>(base_address + entries[i]); 87 patch_relr(patch_ptr); 88 ++patch_ptr; 89 } else { 90 unsigned j = 0; 91 for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j) 92 if (bitmap & 1u) 93 patch_relr(patch_ptr + j); 94 95 patch_ptr += 8 * sizeof(FlatPtr) - 1; 96 } 97 } 98 return true; 99} 100}