[2573] | 1 | #ifndef ELF_HPP |
---|
| 2 | #define ELF_HPP |
---|
| 3 | |
---|
| 4 | #include "common.hpp" |
---|
| 5 | |
---|
| 6 | #if IS_LINUX |
---|
| 7 | #include <array> |
---|
| 8 | #include <cstdint> |
---|
| 9 | #include <cstdio> |
---|
| 10 | #include <cstring> |
---|
| 11 | |
---|
| 12 | #include <elf.h> |
---|
| 13 | |
---|
| 14 | template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> |
---|
| 15 | T elf_byteswap_if_needed(T value, bool elf_is_little) { |
---|
| 16 | if(is_little_endian() == elf_is_little) { |
---|
| 17 | return value; |
---|
| 18 | } else { |
---|
| 19 | return byteswap(value); |
---|
| 20 | } |
---|
| 21 | } |
---|
| 22 | |
---|
| 23 | // TODO: Address code duplication here. Do we actually have to care about 32-bit if the library is compiled as 64-bit? |
---|
| 24 | // I think probably not... |
---|
| 25 | |
---|
| 26 | // TODO: Re-evaluate use of off_t |
---|
| 27 | // I think we can rely on PT_PHDR https://stackoverflow.com/q/61568612/15675011... |
---|
| 28 | static uintptr_t elf_get_module_image_base_from_program_table( |
---|
| 29 | FILE* file, |
---|
| 30 | bool is_64, |
---|
| 31 | bool is_little_endian, |
---|
| 32 | off_t e_phoff, |
---|
| 33 | off_t e_phentsize, |
---|
| 34 | int e_phnum |
---|
| 35 | ) { |
---|
| 36 | for(int i = 0; i < e_phnum; i++) { |
---|
| 37 | if(is_64) { |
---|
| 38 | Elf64_Phdr program_header = load_bytes<Elf64_Phdr>(file, e_phoff + e_phentsize * i); |
---|
| 39 | if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) { |
---|
| 40 | return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian) |
---|
| 41 | - elf_byteswap_if_needed(program_header.p_offset, is_little_endian); |
---|
| 42 | } |
---|
| 43 | } else { |
---|
| 44 | Elf32_Phdr program_header = load_bytes<Elf32_Phdr>(file, e_phoff + e_phentsize * i); |
---|
| 45 | if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) { |
---|
| 46 | return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian) |
---|
| 47 | - elf_byteswap_if_needed(program_header.p_offset, is_little_endian); |
---|
| 48 | } |
---|
| 49 | } |
---|
| 50 | } |
---|
| 51 | return 0; |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | static uintptr_t elf_get_module_image_base(const std::string& obj_path) { |
---|
| 55 | FILE* file = fopen(obj_path.c_str(), "rb"); |
---|
| 56 | if(file == nullptr) { |
---|
| 57 | throw file_error(); |
---|
| 58 | } |
---|
| 59 | // Initial checks/metadata |
---|
| 60 | auto magic = load_bytes<std::array<char, 4>>(file, 0); |
---|
| 61 | internal_verify(magic == (std::array<char, 4>{0x7F, 'E', 'L', 'F'})); |
---|
| 62 | bool is_64 = load_bytes<uint8_t>(file, 4) == 2; |
---|
| 63 | bool is_little_endian = load_bytes<uint8_t>(file, 5) == 1; |
---|
| 64 | internal_verify(load_bytes<uint8_t>(file, 6) == 1, "Unexpected ELF version"); |
---|
| 65 | // |
---|
| 66 | if(is_64) { |
---|
| 67 | Elf64_Ehdr file_header = load_bytes<Elf64_Ehdr>(file, 0); |
---|
| 68 | internal_verify(file_header.e_ehsize == sizeof(Elf64_Ehdr)); |
---|
| 69 | return elf_get_module_image_base_from_program_table( |
---|
| 70 | file, |
---|
| 71 | is_64, |
---|
| 72 | is_little_endian, |
---|
| 73 | elf_byteswap_if_needed(file_header.e_phoff, is_little_endian), |
---|
| 74 | elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian), |
---|
| 75 | elf_byteswap_if_needed(file_header.e_phnum, is_little_endian) |
---|
| 76 | ); |
---|
| 77 | } else { |
---|
| 78 | Elf32_Ehdr file_header = load_bytes<Elf32_Ehdr>(file, 0); |
---|
| 79 | internal_verify(file_header.e_ehsize == sizeof(Elf32_Ehdr)); |
---|
| 80 | return elf_get_module_image_base_from_program_table( |
---|
| 81 | file, |
---|
| 82 | is_64, |
---|
| 83 | is_little_endian, |
---|
| 84 | elf_byteswap_if_needed(file_header.e_phoff, is_little_endian), |
---|
| 85 | elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian), |
---|
| 86 | elf_byteswap_if_needed(file_header.e_phnum, is_little_endian) |
---|
| 87 | ); |
---|
| 88 | } |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | #endif |
---|
| 92 | |
---|
| 93 | #endif |
---|