mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 20:42:43 +00:00 
			
		
		
		
	 45d81dceed
			
		
	
	
		45d81dceed
		
	
	
	
	
		
			
			This works around a `clang-format-17` bug which caused certain usages to be misformatted and fail to compile. Fixes #8315
		
			
				
	
	
		
			100 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include <LibELF/ELFABI.h>
 | |
| #include <LibELF/Relocation.h>
 | |
| 
 | |
| namespace ELF {
 | |
| 
 | |
| bool perform_relative_relocations(FlatPtr base_address)
 | |
| {
 | |
| 
 | |
|     Elf_Ehdr* header = (Elf_Ehdr*)(base_address);
 | |
|     Elf_Phdr* pheader = (Elf_Phdr*)(base_address + header->e_phoff);
 | |
|     FlatPtr dynamic_section_addr = 0;
 | |
|     for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) {
 | |
|         if (pheader->p_type != PT_DYNAMIC)
 | |
|             continue;
 | |
|         dynamic_section_addr = pheader->p_vaddr + base_address;
 | |
|     }
 | |
|     if (!dynamic_section_addr)
 | |
|         return false;
 | |
| 
 | |
|     FlatPtr relocation_section_addr = 0;
 | |
|     size_t relocation_table_size = 0;
 | |
|     size_t relocation_count = 0;
 | |
|     size_t relocation_entry_size = 0;
 | |
|     FlatPtr relr_relocation_section_addr = 0;
 | |
|     size_t relr_relocation_table_size = 0;
 | |
|     bool use_addend = false;
 | |
|     auto* dyns = reinterpret_cast<Elf_Dyn const*>(dynamic_section_addr);
 | |
|     for (unsigned i = 0;; ++i) {
 | |
|         auto& dyn = dyns[i];
 | |
|         if (dyn.d_tag == DT_NULL)
 | |
|             break;
 | |
|         if (dyn.d_tag == DT_RELA)
 | |
|             use_addend = true;
 | |
|         if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELA)
 | |
|             relocation_section_addr = base_address + dyn.d_un.d_ptr;
 | |
|         else if (dyn.d_tag == DT_RELCOUNT || dyn.d_tag == DT_RELACOUNT)
 | |
|             relocation_count = dyn.d_un.d_val;
 | |
|         else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
 | |
|             relocation_table_size = dyn.d_un.d_val;
 | |
|         else if (dyn.d_tag == DT_RELENT || dyn.d_tag == DT_RELAENT)
 | |
|             relocation_entry_size = dyn.d_un.d_val;
 | |
|         else if (dyn.d_tag == DT_RELR)
 | |
|             relr_relocation_section_addr = base_address + dyn.d_un.d_ptr;
 | |
|         else if (dyn.d_tag == DT_RELRSZ)
 | |
|             relr_relocation_table_size = dyn.d_un.d_val;
 | |
|         else if (dyn.d_tag == DT_RELRENT)
 | |
|             VERIFY(dyn.d_un.d_val == sizeof(FlatPtr));
 | |
|     }
 | |
| 
 | |
|     if ((!relocation_section_addr || !relocation_table_size || !relocation_count) && (!relr_relocation_section_addr || !relr_relocation_table_size))
 | |
|         return false;
 | |
| 
 | |
|     for (unsigned i = 0; i < relocation_count; ++i) {
 | |
|         size_t offset_in_section = i * relocation_entry_size;
 | |
|         auto* relocation = (Elf_Rela*)(relocation_section_addr + offset_in_section);
 | |
|         VERIFY(ELF64_R_TYPE(relocation->r_info) == R_X86_64_RELATIVE || ELF64_R_TYPE(relocation->r_info) == R_AARCH64_RELATIVE);
 | |
|         auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset);
 | |
|         FlatPtr relocated_address;
 | |
|         if (use_addend) {
 | |
|             relocated_address = base_address + relocation->r_addend;
 | |
|         } else {
 | |
|             __builtin_memcpy(&relocated_address, patch_address, sizeof(relocated_address));
 | |
|             relocated_address += base_address;
 | |
|         }
 | |
|         __builtin_memcpy(patch_address, &relocated_address, sizeof(relocated_address));
 | |
|     }
 | |
| 
 | |
|     auto patch_relr = [base_address](FlatPtr* patch_ptr) {
 | |
|         FlatPtr relocated_address;
 | |
|         __builtin_memcpy(&relocated_address, patch_ptr, sizeof(FlatPtr));
 | |
|         relocated_address += base_address;
 | |
|         __builtin_memcpy(patch_ptr, &relocated_address, sizeof(FlatPtr));
 | |
|     };
 | |
| 
 | |
|     auto* entries = reinterpret_cast<Elf_Relr*>(relr_relocation_section_addr);
 | |
|     FlatPtr* patch_ptr = nullptr;
 | |
| 
 | |
|     for (unsigned i = 0; i < relr_relocation_table_size / sizeof(FlatPtr); ++i) {
 | |
|         if ((entries[i] & 1u) == 0) {
 | |
|             patch_ptr = reinterpret_cast<FlatPtr*>(base_address + entries[i]);
 | |
|             patch_relr(patch_ptr);
 | |
|             ++patch_ptr;
 | |
|         } else {
 | |
|             unsigned j = 0;
 | |
|             for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j)
 | |
|                 if (bitmap & 1u)
 | |
|                     patch_relr(patch_ptr + j);
 | |
| 
 | |
|             patch_ptr += 8 * sizeof(FlatPtr) - 1;
 | |
|         }
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| }
 |