mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-07 13:00:15 +02:00
Fixes #2136 This is a fairly tricky edge case to support with FEX. If execveat is used with AT_EMPTY_PATH then the application can pass an FD to execve instead of a filename. This includes FDs that have been deleted from the disk so the child process can't open it by filename anymore. To work around this limitation, we need to pass the FD to the new FEX process and open it directly, similar to how binfmt_misc works with FDs. The FD will get passed through environment variables, which the new process will check for and then remove the variable from the environment. Lots of prickly edge cases to support here. Without binfmt_misc: - Passes the FD to FEXLoader directly. - Requires duplicating the FD if it has O_CLOEXEC on the FD. With binfmt_misc: - Shebang file, pass directly to FEXLoader, just like without binfmt. - x86 ELF Files, rely on the kernel's binfmt_misc support here. - Unsupported ELF files, let kernel handle it through binfmt_misc Argument handling: - The application can pass in no arguments. - Means our application configurations were failing to find a config - Also various checks in the frontend were failing. - If opened through an FD, find the symlink for that FD for the application configuration instead. Side note: Fixed a performance issue in execve where when we were checking for file format support. Either ELF or Shebang files, we were reading the /whole/ file upfront. We only need to read a header worth of ELF files, and only 257 bytes if it is potentially a shebang file. Should dramatically reduce some application's execve times.
1356 lines
50 KiB
C++
1356 lines
50 KiB
C++
/*
|
|
$info$
|
|
tags: glue|elf-parsing
|
|
desc: Loads and parses an elf to memory. Also handles some loading & logic.
|
|
$end_info$
|
|
*/
|
|
|
|
#include "Linux/Utils/ELFContainer.h"
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
#include <FEXCore/Utils/MathUtils.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <elf.h>
|
|
#include <fcntl.h>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <system_error>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
|
|
namespace ELFLoader {
|
|
|
|
static ELFContainer::ELFType CheckELFType(uint8_t* Data) {
|
|
if (Data[EI_MAG0] != ELFMAG0 ||
|
|
Data[EI_MAG1] != ELFMAG1 ||
|
|
Data[EI_MAG2] != ELFMAG2 ||
|
|
Data[EI_MAG3] != ELFMAG3) {
|
|
return ELFContainer::ELFType::TYPE_NONE;
|
|
}
|
|
|
|
if (Data[EI_CLASS] == ELFCLASS32) {
|
|
Elf32_Ehdr *Header = reinterpret_cast<Elf32_Ehdr *>(Data);
|
|
if (Header->e_machine == EM_386) {
|
|
return ELFContainer::ELFType::TYPE_X86_32;
|
|
}
|
|
}
|
|
else if (Data[EI_CLASS] == ELFCLASS64) {
|
|
Elf64_Ehdr *Header = reinterpret_cast<Elf64_Ehdr *>(Data);
|
|
if (Header->e_machine == EM_X86_64) {
|
|
return ELFContainer::ELFType::TYPE_X86_64;
|
|
}
|
|
}
|
|
|
|
return ELFContainer::ELFType::TYPE_OTHER_ELF;
|
|
}
|
|
|
|
ELFContainer::ELFType ELFContainer::GetELFType(std::string const &Filename) {
|
|
// Open the Filename to determine if it is a shebang file.
|
|
int FD = open(Filename.c_str(), O_RDONLY | O_CLOEXEC);
|
|
if (FD == -1) {
|
|
return ELFType::TYPE_NONE;
|
|
}
|
|
|
|
auto ELFType = GetELFType(FD);
|
|
close(FD);
|
|
return ELFType;
|
|
}
|
|
|
|
ELFContainer::ELFType ELFContainer::GetELFType(int FD) {
|
|
// We don't know the state of the FD coming in since this might be a guest tracked FD.
|
|
// Need to be extra careful here not to adjust file offsets and status flags.
|
|
//
|
|
// We can't use dup since that makes the FD have the same underlying state backing both FDs.
|
|
|
|
// We need to first determine the file size through fstat.
|
|
struct stat buf{};
|
|
if (fstat(FD, &buf) == -1) {
|
|
// Couldn't get size.
|
|
return ELFType::TYPE_NONE;
|
|
}
|
|
|
|
constexpr size_t ELFHeaderSize = std::max(sizeof(Elf32_Ehdr), sizeof(Elf64_Ehdr));
|
|
if (buf.st_size < ELFHeaderSize) {
|
|
// Is not a valid ELF.
|
|
return ELFType::TYPE_NONE;
|
|
}
|
|
|
|
std::array<char, ELFHeaderSize> RawFile;
|
|
|
|
// Read the header so we can tell if it is a supported ELF file.
|
|
// Can't adjust file offset, so use pread.
|
|
if (pread(FD, &RawFile.at(0), RawFile.size(), 0) != RawFile.size()) {
|
|
// Couldn't read
|
|
LogMan::Msg::EFmt("Couldn't read potential ELF FD");
|
|
return ELFType::TYPE_NONE;
|
|
}
|
|
|
|
return CheckELFType(reinterpret_cast<uint8_t*>(&RawFile.at(0)));
|
|
}
|
|
|
|
ELFContainer::ELFContainer(std::string const &Filename, std::string const &RootFS, bool CustomInterpreter) {
|
|
Loaded = true;
|
|
if (!LoadELF(Filename)) {
|
|
LogMan::Msg::EFmt("Couldn't Load ELF file");
|
|
Loaded = false;
|
|
return;
|
|
}
|
|
|
|
if (InterpreterHeader._64 && !CustomInterpreter) {
|
|
// If we we are dynamic application then we have an interpreter program header
|
|
// We need to load that ELF instead if it exists
|
|
// We are no longer dynamic since we are executing the interpreter
|
|
const char *RawString{};
|
|
if (Mode == MODE_32BIT) {
|
|
RawString = &RawFile.at(InterpreterHeader._32->p_offset);
|
|
}
|
|
else {
|
|
RawString = &RawFile.at(InterpreterHeader._64->p_offset);
|
|
}
|
|
std::string RootFSLink = RootFS + RawString;
|
|
std::error_code ec{};
|
|
while (std::filesystem::is_symlink(RootFSLink, ec)) {
|
|
// Do some special handling if the RootFS's linker is a symlink
|
|
// Ubuntu's rootFS by default provides an absolute location symlink to the linker
|
|
// Resolve this around back to the rootfs
|
|
auto SymlinkTarget = std::filesystem::read_symlink(RootFSLink, ec);
|
|
if (SymlinkTarget.is_absolute()) {
|
|
RootFSLink = RootFS + SymlinkTarget.string();
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
if (LoadELF(RootFSLink)) {
|
|
// Found the interpreter in the rootfs
|
|
}
|
|
else if (!LoadELF(RawString)) {
|
|
LogMan::Msg::EFmt("Failed to find guest ELF's interpter '{}'", RawString);
|
|
LogMan::Msg::EFmt("Did you forget to set an x86 rootfs? Currently '{}'", RootFS);
|
|
Loaded = false;
|
|
return;
|
|
}
|
|
}
|
|
else if (InterpreterHeader._64) {
|
|
GetDynamicLibs();
|
|
}
|
|
|
|
|
|
CalculateMemoryLayouts();
|
|
CalculateSymbols();
|
|
|
|
// Print Information
|
|
// PrintHeader();
|
|
//PrintSectionHeaders();
|
|
//PrintProgramHeaders();
|
|
//PrintSymbolTable();
|
|
//PrintRelocationTable();
|
|
//PrintInitArray();
|
|
//PrintDynamicTable();
|
|
|
|
//LOGMAN_THROW_AA_FMT(InterpreterHeader == nullptr, "Can only handle static programs");
|
|
}
|
|
|
|
ELFContainer::~ELFContainer() {
|
|
NecessaryLibs.clear();
|
|
SymbolMapByAddress.clear();
|
|
SymbolMap.clear();
|
|
Symbols.clear();
|
|
ProgramHeaders.clear();
|
|
SectionHeaders.clear();
|
|
RawFile.clear();
|
|
}
|
|
|
|
bool ELFContainer::LoadELF(std::string const &Filename) {
|
|
std::fstream ELFFile(Filename, std::fstream::in | std::fstream::binary);
|
|
|
|
if (!ELFFile.is_open())
|
|
return false;
|
|
|
|
ELFFile.seekg(0, ELFFile.end);
|
|
size_t FileSize = ELFFile.tellg();
|
|
ELFFile.seekg(0, ELFFile.beg);
|
|
|
|
RawFile.resize(FileSize);
|
|
ELFFile.read(RawFile.data(), FileSize);
|
|
ELFFile.close();
|
|
|
|
InterpreterHeader._64 = nullptr;
|
|
|
|
SectionHeaders.clear();
|
|
ProgramHeaders.clear();
|
|
|
|
uint8_t *Ident = reinterpret_cast<uint8_t*>(&RawFile.at(0));
|
|
|
|
if (Ident[EI_MAG0] != ELFMAG0 ||
|
|
Ident[EI_MAG1] != ELFMAG1 ||
|
|
Ident[EI_MAG2] != ELFMAG2 ||
|
|
Ident[EI_MAG3] != ELFMAG3) {
|
|
LogMan::Msg::EFmt("ELF missing magic cookie");
|
|
return false;
|
|
}
|
|
|
|
if (Ident[EI_CLASS] == ELFCLASS32) {
|
|
return LoadELF_32();
|
|
}
|
|
else if (Ident[EI_CLASS] == ELFCLASS64) {
|
|
return LoadELF_64();
|
|
}
|
|
|
|
LogMan::Msg::EFmt("Unknown ELF type");
|
|
return false;
|
|
}
|
|
|
|
bool ELFContainer::LoadELF_32() {
|
|
Mode = MODE_32BIT;
|
|
|
|
memcpy(&Header, reinterpret_cast<Elf32_Ehdr *>(&RawFile.at(0)),
|
|
sizeof(Elf32_Ehdr));
|
|
LOGMAN_THROW_AA_FMT(Header._32.e_phentsize == sizeof(Elf32_Phdr), "PH Entry size wasn't correct size");
|
|
LOGMAN_THROW_AA_FMT(Header._32.e_shentsize == sizeof(Elf32_Shdr), "PH Entry size wasn't correct size");
|
|
|
|
if (Header._32.e_machine != EM_386) {
|
|
LogMan::Msg::DFmt("32bit ELF wasn't x86 based");
|
|
return false;
|
|
}
|
|
|
|
SectionHeaders.resize(Header._32.e_shnum);
|
|
ProgramHeaders.resize(Header._32.e_phnum);
|
|
|
|
Elf32_Shdr *RawShdrs =
|
|
reinterpret_cast<Elf32_Shdr *>(&RawFile.at(Header._32.e_shoff));
|
|
Elf32_Phdr *RawPhdrs =
|
|
reinterpret_cast<Elf32_Phdr *>(&RawFile.at(Header._32.e_phoff));
|
|
|
|
for (uint32_t i = 0; i < Header._32.e_shnum; ++i) {
|
|
SectionHeaders[i]._32 = &RawShdrs[i];
|
|
}
|
|
|
|
for (uint32_t i = 0; i < Header._32.e_phnum; ++i) {
|
|
ProgramHeaders[i]._32 = &RawPhdrs[i];
|
|
if (ProgramHeaders[i]._32->p_type == PT_INTERP) {
|
|
InterpreterHeader = ProgramHeaders[i];
|
|
DynamicLinker = reinterpret_cast<char const*>(&RawFile.at(InterpreterHeader._32->p_offset));
|
|
}
|
|
}
|
|
|
|
DynamicProgram = Header._32.e_type != ET_EXEC;
|
|
|
|
// Default BRK size
|
|
BRKSize = 4096;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ELFContainer::LoadELF_64() {
|
|
Mode = MODE_64BIT;
|
|
|
|
memcpy(&Header, reinterpret_cast<Elf64_Ehdr *>(&RawFile.at(0)),
|
|
sizeof(Elf64_Ehdr));
|
|
LOGMAN_THROW_AA_FMT(Header._64.e_phentsize == 56, "PH Entry size wasn't 56");
|
|
LOGMAN_THROW_AA_FMT(Header._64.e_shentsize == 64, "PH Entry size wasn't 64");
|
|
|
|
if (Header._64.e_machine != EM_X86_64) {
|
|
LogMan::Msg::DFmt("64bit ELF wasn't x86-64 based");
|
|
return false;
|
|
}
|
|
|
|
SectionHeaders.resize(Header._64.e_shnum);
|
|
ProgramHeaders.resize(Header._64.e_phnum);
|
|
|
|
Elf64_Shdr *RawShdrs =
|
|
reinterpret_cast<Elf64_Shdr *>(&RawFile.at(Header._64.e_shoff));
|
|
Elf64_Phdr *RawPhdrs =
|
|
reinterpret_cast<Elf64_Phdr *>(&RawFile.at(Header._64.e_phoff));
|
|
|
|
for (uint32_t i = 0; i < Header._64.e_shnum; ++i) {
|
|
SectionHeaders[i]._64 = &RawShdrs[i];
|
|
}
|
|
|
|
for (uint32_t i = 0; i < Header._64.e_phnum; ++i) {
|
|
ProgramHeaders[i]._64 = &RawPhdrs[i];
|
|
if (ProgramHeaders[i]._64->p_type == PT_INTERP) {
|
|
InterpreterHeader = ProgramHeaders[i];
|
|
DynamicLinker = reinterpret_cast<char const*>(&RawFile.at(InterpreterHeader._64->p_offset));
|
|
}
|
|
}
|
|
|
|
DynamicProgram = Header._64.e_type != ET_EXEC;
|
|
|
|
// Default BRK size
|
|
BRKSize = 0x1000'0000;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ELFContainer::WriteLoadableSections(MemoryWriter Writer, uint64_t Offset) {
|
|
if (Mode == MODE_32BIT) {
|
|
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
|
|
Elf32_Phdr const *hdr = ProgramHeaders.at(i)._32;
|
|
if (hdr->p_type == PT_LOAD) {
|
|
//LogMan::Msg::DFmt("PT_LOAD: Base: {} Offset: [0x{:x}, 0x{:x})", Offset, hdr->p_paddr, hdr->p_filesz);
|
|
Writer(&RawFile.at(hdr->p_offset), Offset + hdr->p_paddr, hdr->p_filesz);
|
|
}
|
|
|
|
if (hdr->p_type == PT_TLS) {
|
|
Writer(&RawFile.at(hdr->p_offset), Offset + hdr->p_paddr, hdr->p_filesz);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
|
|
Elf64_Phdr const *hdr = ProgramHeaders.at(i)._64;
|
|
if (hdr->p_type == PT_LOAD) {
|
|
Writer(&RawFile.at(hdr->p_offset), Offset + hdr->p_paddr, hdr->p_filesz);
|
|
}
|
|
|
|
if (hdr->p_type == PT_TLS) {
|
|
Writer(&RawFile.at(hdr->p_offset), Offset + hdr->p_paddr, hdr->p_filesz);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ELFSymbol const *ELFContainer::GetSymbol(char const *Name) {
|
|
auto Sym = SymbolMap.find(Name);
|
|
if (Sym == SymbolMap.end())
|
|
return nullptr;
|
|
return Sym->second;
|
|
}
|
|
ELFSymbol const *ELFContainer::GetSymbol(uint64_t Address) {
|
|
auto Sym = SymbolMapByAddress.find(Address);
|
|
if (Sym == SymbolMapByAddress.end())
|
|
return nullptr;
|
|
return Sym->second;
|
|
}
|
|
ELFSymbol const *ELFContainer::GetSymbolInRange(RangeType Address) {
|
|
auto Sym = SymbolMapByAddress.upper_bound(Address.first);
|
|
if (Sym != SymbolMapByAddress.begin())
|
|
--Sym;
|
|
if (Sym == SymbolMapByAddress.end())
|
|
return nullptr;
|
|
|
|
if ((Sym->second->Address + Sym->second->Size) < Address.first)
|
|
return nullptr;
|
|
|
|
return Sym->second;
|
|
}
|
|
|
|
void ELFContainer::CalculateMemoryLayouts() {
|
|
uint64_t MinPhysAddr = ~0ULL;
|
|
uint64_t MaxPhysAddr = 0;
|
|
uint64_t PhysMemSize = 0;
|
|
|
|
if (Mode == MODE_32BIT) {
|
|
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
|
|
Elf32_Phdr *hdr = ProgramHeaders.at(i)._32;
|
|
if (hdr->p_memsz > 0) {
|
|
MinPhysAddr = std::min(MinPhysAddr, static_cast<uint64_t>(hdr->p_paddr));
|
|
MaxPhysAddr = std::max(MaxPhysAddr, static_cast<uint64_t>(hdr->p_paddr) + hdr->p_memsz);
|
|
}
|
|
if (hdr->p_type == PT_TLS) {
|
|
TLSHeader._32 = hdr;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
|
|
Elf64_Phdr *hdr = ProgramHeaders.at(i)._64;
|
|
|
|
// Many elfs have program region labeled .GNU_STACK which is empty and has a null address.
|
|
// It's used to mark the memory protection flags of the stack.
|
|
//
|
|
// We need to ignore such empty sections, or we will mistakenly assume the elf starts at zero.
|
|
if (hdr->p_memsz > 0) {
|
|
MinPhysAddr = std::min(MinPhysAddr, static_cast<uint64_t>(hdr->p_paddr));
|
|
MaxPhysAddr = std::max(MaxPhysAddr, static_cast<uint64_t>(hdr->p_paddr + hdr->p_memsz));
|
|
}
|
|
if (hdr->p_type == PT_TLS) {
|
|
TLSHeader._64 = hdr;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate BRK
|
|
MaxPhysAddr = FEXCore::AlignUp(MaxPhysAddr, 4096);
|
|
BRKBase = MaxPhysAddr;
|
|
MaxPhysAddr += BRKSize;
|
|
|
|
PhysMemSize = MaxPhysAddr - MinPhysAddr;
|
|
|
|
MinPhysicalMemoryLocation = MinPhysAddr;
|
|
MaxPhysicalMemoryLocation = MaxPhysAddr;
|
|
PhysicalMemorySize = PhysMemSize;
|
|
}
|
|
|
|
void ELFContainer::CalculateSymbols() {
|
|
// Find the symbol table
|
|
if (Mode == MODE_32BIT) {
|
|
Elf32_Shdr const *SymTabHeader{nullptr};
|
|
Elf32_Shdr const *StringTableHeader{nullptr};
|
|
char const *StrTab{nullptr};
|
|
|
|
Elf32_Shdr const *DynSymTabHeader{nullptr};
|
|
Elf32_Shdr const *DynStringTableHeader{nullptr};
|
|
char const *DynStrTab{nullptr};
|
|
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
|
if (hdr->sh_type == SHT_SYMTAB) {
|
|
SymTabHeader = hdr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
|
if (hdr->sh_type == SHT_DYNSYM) {
|
|
DynSymTabHeader = hdr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!SymTabHeader && !DynSymTabHeader) {
|
|
LogMan::Msg::IFmt("No Symbol table");
|
|
return;
|
|
}
|
|
|
|
uint64_t NumSymTabSymbols = 0;
|
|
uint64_t NumDynSymSymbols = 0;
|
|
if (SymTabHeader) {
|
|
LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(),
|
|
"Symbol table string table section is wrong");
|
|
LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
|
"Entry size doesn't match symbol entry");
|
|
|
|
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32;
|
|
StrTab = &RawFile.at(StringTableHeader->sh_offset);
|
|
NumSymTabSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize;
|
|
}
|
|
|
|
if (DynSymTabHeader) {
|
|
LOGMAN_THROW_A_FMT(DynSymTabHeader->sh_link < SectionHeaders.size(),
|
|
"Symbol table string table section is wrong");
|
|
LOGMAN_THROW_AA_FMT(DynSymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
|
"Entry size doesn't match symbol entry");
|
|
|
|
DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._32;
|
|
DynStrTab = &RawFile.at(DynStringTableHeader->sh_offset);
|
|
NumDynSymSymbols = DynSymTabHeader->sh_size / DynSymTabHeader->sh_entsize;
|
|
}
|
|
|
|
uint64_t NumSymbols = NumSymTabSymbols + NumDynSymSymbols;
|
|
|
|
Symbols.resize(NumSymbols);
|
|
for (uint64_t i = 0; i < NumSymTabSymbols; ++i) {
|
|
uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize;
|
|
Elf32_Sym const *Symbol =
|
|
reinterpret_cast<Elf32_Sym const *>(&RawFile.at(offset));
|
|
if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN &&
|
|
Symbol->st_value != 0) {
|
|
char const * Name = &StrTab[Symbol->st_name];
|
|
if (Name[0] != '\0') {
|
|
ELFSymbol *DefinedSymbol = &Symbols.at(i);
|
|
DefinedSymbol->FileOffset = offset;
|
|
DefinedSymbol->Address = Symbol->st_value;
|
|
DefinedSymbol->Size = Symbol->st_size;
|
|
DefinedSymbol->Type = ELF32_ST_TYPE(Symbol->st_info);
|
|
DefinedSymbol->Bind = ELF32_ST_BIND(Symbol->st_info);
|
|
DefinedSymbol->Name = Name;
|
|
DefinedSymbol->SectionIndex = Symbol->st_shndx;
|
|
|
|
SymbolMap[DefinedSymbol->Name] = DefinedSymbol;
|
|
SymbolMapByAddress[DefinedSymbol->Address] = DefinedSymbol;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (uint64_t i = 0; i < NumDynSymSymbols; ++i) {
|
|
uint64_t offset = DynSymTabHeader->sh_offset + i * DynSymTabHeader->sh_entsize;
|
|
Elf32_Sym const *Symbol =
|
|
reinterpret_cast<Elf32_Sym const *>(&RawFile.at(offset));
|
|
if (ELF32_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN &&
|
|
Symbol->st_value != 0) {
|
|
char const * Name = &DynStrTab[Symbol->st_name];
|
|
if (Name[0] != '\0') {
|
|
ELFSymbol *DefinedSymbol = &Symbols.at(NumSymTabSymbols + i);
|
|
DefinedSymbol->FileOffset = offset;
|
|
DefinedSymbol->Address = Symbol->st_value;
|
|
DefinedSymbol->Size = Symbol->st_size;
|
|
DefinedSymbol->Type = ELF32_ST_TYPE(Symbol->st_info);
|
|
DefinedSymbol->Bind = ELF32_ST_BIND(Symbol->st_info);
|
|
DefinedSymbol->Name = Name;
|
|
DefinedSymbol->SectionIndex = Symbol->st_shndx;
|
|
|
|
SymbolMap[DefinedSymbol->Name] = DefinedSymbol;
|
|
SymbolMapByAddress[DefinedSymbol->Address] = DefinedSymbol;
|
|
}
|
|
}
|
|
}
|
|
|
|
Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32;
|
|
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
|
if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) {
|
|
auto eh_frame_hdr = &RawFile.at(hdr->sh_offset);
|
|
// we only handle this specific unwind table encoding
|
|
if (eh_frame_hdr[0] == 1 && eh_frame_hdr[1] == 0x1B && eh_frame_hdr[2] == 0x3 && eh_frame_hdr[3] == 0x3b) {
|
|
// ptr enc : 4 bytes, signed, pcrel
|
|
// fde count : 4 bytes udata
|
|
// table enc : 4 bytes, signed, datarel
|
|
int fde_count = *(int*)(eh_frame_hdr + 8);
|
|
UnwindEntries.clear();
|
|
UnwindEntries.reserve(fde_count);
|
|
|
|
struct entry {
|
|
int32_t pc;
|
|
int32_t fde;
|
|
};
|
|
|
|
entry *Table = (entry*)(eh_frame_hdr+12);
|
|
for (int f = 0; f < fde_count; f++) {
|
|
uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset);
|
|
UnwindEntries.push_back(Entry);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Elf64_Shdr const *SymTabHeader{nullptr};
|
|
Elf64_Shdr const *StringTableHeader{nullptr};
|
|
char const *StrTab{nullptr};
|
|
|
|
Elf64_Shdr const *DynSymTabHeader{nullptr};
|
|
Elf64_Shdr const *DynStringTableHeader{nullptr};
|
|
char const *DynStrTab{nullptr};
|
|
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (hdr->sh_type == SHT_SYMTAB) {
|
|
SymTabHeader = hdr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (hdr->sh_type == SHT_DYNSYM) {
|
|
DynSymTabHeader = hdr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!SymTabHeader && !DynSymTabHeader) {
|
|
LogMan::Msg::IFmt("No Symbol table");
|
|
return;
|
|
}
|
|
|
|
uint64_t NumSymTabSymbols = 0;
|
|
uint64_t NumDynSymSymbols = 0;
|
|
if (SymTabHeader) {
|
|
LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(),
|
|
"Symbol table string table section is wrong");
|
|
LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
|
"Entry size doesn't match symbol entry");
|
|
|
|
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64;
|
|
StrTab = &RawFile.at(StringTableHeader->sh_offset);
|
|
NumSymTabSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize;
|
|
}
|
|
|
|
if (DynSymTabHeader) {
|
|
LOGMAN_THROW_A_FMT(DynSymTabHeader->sh_link < SectionHeaders.size(),
|
|
"Symbol table string table section is wrong");
|
|
LOGMAN_THROW_AA_FMT(DynSymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
|
"Entry size doesn't match symbol entry");
|
|
|
|
DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._64;
|
|
DynStrTab = &RawFile.at(DynStringTableHeader->sh_offset);
|
|
NumDynSymSymbols = DynSymTabHeader->sh_size / DynSymTabHeader->sh_entsize;
|
|
}
|
|
|
|
uint64_t NumSymbols = NumSymTabSymbols + NumDynSymSymbols;
|
|
|
|
Symbols.resize(NumSymbols);
|
|
for (uint64_t i = 0; i < NumSymTabSymbols; ++i) {
|
|
uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize;
|
|
Elf64_Sym const *Symbol =
|
|
reinterpret_cast<Elf64_Sym const *>(&RawFile.at(offset));
|
|
if (ELF64_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN &&
|
|
Symbol->st_value != 0) {
|
|
char const * Name = &StrTab[Symbol->st_name];
|
|
if (Name[0] != '\0') {
|
|
ELFSymbol *DefinedSymbol = &Symbols.at(i);
|
|
DefinedSymbol->FileOffset = offset;
|
|
DefinedSymbol->Address = Symbol->st_value;
|
|
DefinedSymbol->Size = Symbol->st_size;
|
|
DefinedSymbol->Type = ELF64_ST_TYPE(Symbol->st_info);
|
|
DefinedSymbol->Bind = ELF64_ST_BIND(Symbol->st_info);
|
|
DefinedSymbol->Name = Name;
|
|
DefinedSymbol->SectionIndex = Symbol->st_shndx;
|
|
|
|
SymbolMap[DefinedSymbol->Name] = DefinedSymbol;
|
|
SymbolMapByAddress[DefinedSymbol->Address] = DefinedSymbol;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (uint64_t i = 0; i < NumDynSymSymbols; ++i) {
|
|
uint64_t offset = DynSymTabHeader->sh_offset + i * DynSymTabHeader->sh_entsize;
|
|
Elf64_Sym const *Symbol =
|
|
reinterpret_cast<Elf64_Sym const *>(&RawFile.at(offset));
|
|
if (ELF64_ST_VISIBILITY(Symbol->st_other) != STV_HIDDEN &&
|
|
Symbol->st_value != 0) {
|
|
char const * Name = &DynStrTab[Symbol->st_name];
|
|
if (Name[0] != '\0') {
|
|
ELFSymbol *DefinedSymbol = &Symbols.at(NumSymTabSymbols + i);
|
|
DefinedSymbol->FileOffset = offset;
|
|
DefinedSymbol->Address = Symbol->st_value;
|
|
DefinedSymbol->Size = Symbol->st_size;
|
|
DefinedSymbol->Type = ELF64_ST_TYPE(Symbol->st_info);
|
|
DefinedSymbol->Bind = ELF64_ST_BIND(Symbol->st_info);
|
|
DefinedSymbol->Name = Name;
|
|
DefinedSymbol->SectionIndex = Symbol->st_shndx;
|
|
|
|
SymbolMap[DefinedSymbol->Name] = DefinedSymbol;
|
|
SymbolMapByAddress[DefinedSymbol->Address] = DefinedSymbol;
|
|
}
|
|
}
|
|
}
|
|
|
|
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64;
|
|
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) {
|
|
auto eh_frame_hdr = &RawFile.at(hdr->sh_offset);
|
|
// we only handle this specific unwind table encoding
|
|
if (eh_frame_hdr[0] == 1 && eh_frame_hdr[1] == 0x1B && eh_frame_hdr[2] == 0x3 && eh_frame_hdr[3] == 0x3b) {
|
|
// ptr enc : 4 bytes, signed, pcrel
|
|
// fde count : 4 bytes udata
|
|
// table enc : 4 bytes, signed, datarel
|
|
int fde_count = *(int*)(eh_frame_hdr + 8);
|
|
UnwindEntries.clear();
|
|
UnwindEntries.reserve(fde_count);
|
|
|
|
struct entry {
|
|
int32_t pc;
|
|
int32_t fde;
|
|
};
|
|
|
|
entry *Table = (entry*)(eh_frame_hdr+12);
|
|
for (int f = 0; f < fde_count; f++) {
|
|
uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset);
|
|
UnwindEntries.push_back(Entry);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::GetDynamicLibs() {
|
|
if (Mode == MODE_32BIT) {
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
|
if (hdr->sh_type == SHT_DYNAMIC) {
|
|
Elf32_Shdr const *StrHeader = SectionHeaders.at(hdr->sh_link)._32;
|
|
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
|
|
size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; i < Entries; ++j) {
|
|
Elf32_Dyn const *Dynamic = reinterpret_cast<Elf32_Dyn const*>(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize));
|
|
if (Dynamic->d_tag == DT_NULL) break;
|
|
if (Dynamic->d_tag == DT_NEEDED) {
|
|
NecessaryLibs.emplace_back(&SHStrings[Dynamic->d_un.d_val]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (hdr->sh_type == SHT_DYNAMIC) {
|
|
Elf64_Shdr const *StrHeader = SectionHeaders.at(hdr->sh_link)._64;
|
|
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
|
|
size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; i < Entries; ++j) {
|
|
Elf64_Dyn const *Dynamic = reinterpret_cast<Elf64_Dyn const*>(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize));
|
|
if (Dynamic->d_tag == DT_NULL) break;
|
|
if (Dynamic->d_tag == DT_NEEDED) {
|
|
NecessaryLibs.emplace_back(&SHStrings[Dynamic->d_un.d_val]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::AddSymbols(SymbolAdder Adder) {
|
|
for (auto &Sym : Symbols) {
|
|
if (Sym.FileOffset) {
|
|
Adder(&Sym);
|
|
}
|
|
}
|
|
}
|
|
void ELFContainer::AddUnwindEntries(UnwindAdder Adder) {
|
|
for (auto Entry : UnwindEntries) {
|
|
Adder(Entry);
|
|
}
|
|
}
|
|
|
|
void ELFContainer::PrintHeader() const {
|
|
if (Mode == MODE_32BIT) {
|
|
LogMan::Msg::IFmt("Type: {}", Header._32.e_type);
|
|
LogMan::Msg::IFmt("Machine: {}", Header._32.e_machine);
|
|
LogMan::Msg::IFmt("Version: {}", Header._32.e_version);
|
|
LogMan::Msg::IFmt("Entry point: 0x{:x}", Header._32.e_entry);
|
|
LogMan::Msg::IFmt("PH Off: {}", Header._32.e_phoff);
|
|
LogMan::Msg::IFmt("SH Off: {}", Header._32.e_shoff);
|
|
LogMan::Msg::IFmt("Flags: {}", Header._32.e_flags);
|
|
LogMan::Msg::IFmt("EH Size: {}", Header._32.e_ehsize);
|
|
LogMan::Msg::IFmt("PH Num: {}", Header._32.e_phnum);
|
|
LogMan::Msg::IFmt("SH Num: {}", Header._32.e_shnum);
|
|
LogMan::Msg::IFmt("PH Entry Size: {}", Header._32.e_phentsize);
|
|
LogMan::Msg::IFmt("SH Entry Size: {}", Header._32.e_shentsize);
|
|
LogMan::Msg::IFmt("SH Str Index: {}", Header._32.e_shstrndx);
|
|
}
|
|
else {
|
|
LogMan::Msg::IFmt("Type: {}", Header._64.e_type);
|
|
LogMan::Msg::IFmt("Machine: {}", Header._64.e_machine);
|
|
LogMan::Msg::IFmt("Version: {}", Header._64.e_version);
|
|
LogMan::Msg::IFmt("Entry point: 0x{:x}", Header._64.e_entry);
|
|
LogMan::Msg::IFmt("PH Off: {}", Header._64.e_phoff);
|
|
LogMan::Msg::IFmt("SH Off: {}", Header._64.e_shoff);
|
|
LogMan::Msg::IFmt("Flags: {}", Header._64.e_flags);
|
|
LogMan::Msg::IFmt("EH Size: {}", Header._64.e_ehsize);
|
|
LogMan::Msg::IFmt("PH Num: {}", Header._64.e_phnum);
|
|
LogMan::Msg::IFmt("SH Num: {}", Header._64.e_shnum);
|
|
LogMan::Msg::IFmt("PH Entry Size: {}", Header._64.e_phentsize);
|
|
LogMan::Msg::IFmt("SH Entry Size: {}", Header._64.e_shentsize);
|
|
LogMan::Msg::IFmt("SH Str Index: {}", Header._64.e_shstrndx);
|
|
}
|
|
}
|
|
|
|
void ELFContainer::PrintSectionHeaders() const {
|
|
if (Mode == MODE_32BIT) {
|
|
LOGMAN_THROW_A_FMT(Header._32.e_shstrndx < SectionHeaders.size(),
|
|
"String index section is wrong index!");
|
|
Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32;
|
|
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
for (size_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders[i]._32;
|
|
LogMan::Msg::IFmt("Index: {}", i);
|
|
LogMan::Msg::IFmt("Name: {}", &SHStrings[hdr->sh_name]);
|
|
LogMan::Msg::IFmt("Type: {}", hdr->sh_type);
|
|
LogMan::Msg::IFmt("Flags: {}", hdr->sh_flags);
|
|
LogMan::Msg::IFmt("Addr: 0x{:x}", hdr->sh_addr);
|
|
LogMan::Msg::IFmt("Offset: 0x{:x}", hdr->sh_offset);
|
|
LogMan::Msg::IFmt("Size: {}", hdr->sh_size);
|
|
LogMan::Msg::IFmt("Link: {}", hdr->sh_link);
|
|
LogMan::Msg::IFmt("Info: {}", hdr->sh_info);
|
|
LogMan::Msg::IFmt("AddrAlign: {}", hdr->sh_addralign);
|
|
LogMan::Msg::IFmt("Entry Size: {}", hdr->sh_entsize);
|
|
}
|
|
}
|
|
else {
|
|
LOGMAN_THROW_A_FMT(Header._64.e_shstrndx < SectionHeaders.size(),
|
|
"String index section is wrong index!");
|
|
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64;
|
|
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
for (size_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders[i]._64;
|
|
LogMan::Msg::IFmt("Index: {}", i);
|
|
LogMan::Msg::IFmt("Name: {}", &SHStrings[hdr->sh_name]);
|
|
LogMan::Msg::IFmt("Type: {}", hdr->sh_type);
|
|
LogMan::Msg::IFmt("Flags: {}", hdr->sh_flags);
|
|
LogMan::Msg::IFmt("Addr: 0x{:x}", hdr->sh_addr);
|
|
LogMan::Msg::IFmt("Offset: 0x{:x}", hdr->sh_offset);
|
|
LogMan::Msg::IFmt("Size: {}", hdr->sh_size);
|
|
LogMan::Msg::IFmt("Link: {}", hdr->sh_link);
|
|
LogMan::Msg::IFmt("Info: {}", hdr->sh_info);
|
|
LogMan::Msg::IFmt("AddrAlign: {}", hdr->sh_addralign);
|
|
LogMan::Msg::IFmt("Entry Size: {}", hdr->sh_entsize);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::PrintProgramHeaders() const {
|
|
if (Mode == MODE_32BIT) {
|
|
LOGMAN_THROW_A_FMT(Header._32.e_shstrndx < SectionHeaders.size(),
|
|
"String index section is wrong index!");
|
|
for (size_t i = 0; i < ProgramHeaders.size(); ++i) {
|
|
Elf32_Phdr const *hdr = ProgramHeaders[i]._32;
|
|
LogMan::Msg::IFmt("Type: {}", hdr->p_type);
|
|
LogMan::Msg::IFmt("Flags: {}", hdr->p_flags);
|
|
LogMan::Msg::IFmt("Offset: {}", hdr->p_offset);
|
|
LogMan::Msg::IFmt("VAddr: 0x{:x}", hdr->p_vaddr);
|
|
LogMan::Msg::IFmt("PAddr: 0x{:x}", hdr->p_paddr);
|
|
LogMan::Msg::IFmt("FSize: {}", hdr->p_filesz);
|
|
LogMan::Msg::IFmt("MemSize: {}", hdr->p_memsz);
|
|
LogMan::Msg::IFmt("Align: {}", hdr->p_align);
|
|
}
|
|
}
|
|
else {
|
|
LOGMAN_THROW_A_FMT(Header._64.e_shstrndx < SectionHeaders.size(),
|
|
"String index section is wrong index!");
|
|
for (size_t i = 0; i < ProgramHeaders.size(); ++i) {
|
|
Elf64_Phdr const *hdr = ProgramHeaders[i]._64;
|
|
LogMan::Msg::IFmt("Type: {}", hdr->p_type);
|
|
LogMan::Msg::IFmt("Flags: {}", hdr->p_flags);
|
|
LogMan::Msg::IFmt("Offset: {}", hdr->p_offset);
|
|
LogMan::Msg::IFmt("VAddr: 0x{:x}", hdr->p_vaddr);
|
|
LogMan::Msg::IFmt("PAddr: 0x{:x}", hdr->p_paddr);
|
|
LogMan::Msg::IFmt("FSize: {}", hdr->p_filesz);
|
|
LogMan::Msg::IFmt("MemSize: {}", hdr->p_memsz);
|
|
LogMan::Msg::IFmt("Align: {}", hdr->p_align);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::PrintSymbolTable() const {
|
|
if (Mode == MODE_32BIT) {
|
|
// Find the symbol table
|
|
Elf32_Shdr const *SymTabHeader{nullptr};
|
|
Elf32_Shdr const *StringTableHeader{nullptr};
|
|
char const *StrTab{nullptr};
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
|
if (hdr->sh_type == SHT_SYMTAB) {
|
|
SymTabHeader = hdr;
|
|
break;
|
|
}
|
|
}
|
|
if (!SymTabHeader) {
|
|
LogMan::Msg::IFmt("No Symbol table");
|
|
return;
|
|
}
|
|
|
|
LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(),
|
|
"Symbol table string table section is wrong");
|
|
LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
|
"Entry size doesn't match symbol entry");
|
|
|
|
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32;
|
|
StrTab = &RawFile.at(StringTableHeader->sh_offset);
|
|
|
|
const uint64_t NumSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize;
|
|
for (uint64_t i = 0; i < NumSymbols; ++i) {
|
|
const uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize;
|
|
const auto *Symbol = reinterpret_cast<const Elf32_Sym *>(&RawFile.at(offset));
|
|
|
|
LogMan::Msg::IFmt("{} : {:x} {} {} {} {} {}", i, Symbol->st_value, Symbol->st_size,
|
|
uint32_t(Symbol->st_info), uint32_t(Symbol->st_other),
|
|
Symbol->st_shndx, &StrTab[Symbol->st_name]);
|
|
}
|
|
}
|
|
else {
|
|
// Find the symbol table
|
|
Elf64_Shdr const *SymTabHeader{nullptr};
|
|
Elf64_Shdr const *StringTableHeader{nullptr};
|
|
char const *StrTab{nullptr};
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (hdr->sh_type == SHT_SYMTAB) {
|
|
SymTabHeader = hdr;
|
|
break;
|
|
}
|
|
}
|
|
if (!SymTabHeader) {
|
|
LogMan::Msg::IFmt("No Symbol table");
|
|
return;
|
|
}
|
|
|
|
LOGMAN_THROW_A_FMT(SymTabHeader->sh_link < SectionHeaders.size(),
|
|
"Symbol table string table section is wrong");
|
|
LOGMAN_THROW_AA_FMT(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
|
"Entry size doesn't match symbol entry");
|
|
|
|
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64;
|
|
StrTab = &RawFile.at(StringTableHeader->sh_offset);
|
|
|
|
const uint64_t NumSymbols = SymTabHeader->sh_size / SymTabHeader->sh_entsize;
|
|
for (uint64_t i = 0; i < NumSymbols; ++i) {
|
|
const uint64_t offset = SymTabHeader->sh_offset + i * SymTabHeader->sh_entsize;
|
|
const auto *Symbol = reinterpret_cast<const Elf64_Sym *>(&RawFile.at(offset));
|
|
|
|
LogMan::Msg::IFmt("{} : {:x} {} {} {} {} {}", i, Symbol->st_value, Symbol->st_size,
|
|
uint32_t(Symbol->st_info), uint32_t(Symbol->st_other),
|
|
Symbol->st_shndx, &StrTab[Symbol->st_name]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::PrintRelocationTable() const {
|
|
if (Mode == MODE_32BIT) {
|
|
}
|
|
else {
|
|
Elf64_Shdr const *RelaHeader{nullptr};
|
|
Elf64_Shdr const *DynSymHeader {nullptr};
|
|
|
|
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64;
|
|
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
|
|
Elf64_Shdr const *StringTableHeader{nullptr};
|
|
char const *StrTab{nullptr};
|
|
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (hdr->sh_type == SHT_REL) {
|
|
LogMan::Msg::DFmt("Unhandled REL section");
|
|
}
|
|
else if (hdr->sh_type == SHT_RELA) {
|
|
RelaHeader = hdr;
|
|
LogMan::Msg::DFmt("Relocation Section: '{}'", &SHStrings[RelaHeader->sh_name]);
|
|
|
|
if (RelaHeader->sh_info != 0) {
|
|
LOGMAN_THROW_A_FMT(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
|
|
}
|
|
|
|
if (RelaHeader->sh_link != 0) {
|
|
LOGMAN_THROW_A_FMT(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
|
|
DynSymHeader = SectionHeaders.at(RelaHeader->sh_link)._64;
|
|
|
|
StringTableHeader = SectionHeaders.at(DynSymHeader->sh_link)._64;
|
|
StrTab = &RawFile.at(StringTableHeader->sh_offset);
|
|
}
|
|
|
|
const size_t EntryCount = RelaHeader->sh_size / RelaHeader->sh_entsize;
|
|
const auto *Entries = reinterpret_cast<const Elf64_Rela *>(&RawFile.at(RelaHeader->sh_offset));
|
|
|
|
for (size_t j = 0; j < EntryCount; ++j) {
|
|
const auto *Entry = &Entries[j];
|
|
const uint32_t Sym = Entry->r_info >> 32;
|
|
const uint32_t Type = Entry->r_info & ~0U;
|
|
LogMan::Msg::DFmt("RELA Entry {}", j);
|
|
LogMan::Msg::DFmt("\toffset: 0x{:x}", Entry->r_offset);
|
|
LogMan::Msg::DFmt("\tSym: 0x{:x}", Sym);
|
|
if (DynSymHeader && Sym != 0) {
|
|
LOGMAN_THROW_AA_FMT(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
|
|
|
|
const uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize;
|
|
const auto *Symbol = reinterpret_cast<const Elf64_Sym *>(&RawFile.at(offset));
|
|
LogMan::Msg::DFmt("\tSym Name: '{}'", &StrTab[Symbol->st_name]);
|
|
}
|
|
|
|
LogMan::Msg::DFmt("\tType: 0x{:x}", Type);
|
|
LogMan::Msg::DFmt("\tadded: 0x{:x}", Entry->r_addend);
|
|
if (Type == R_X86_64_IRELATIVE) { // 37/0x25
|
|
LogMan::Msg::DFmt("\tR_x86_64_IRELATIVE");
|
|
}
|
|
else if (Type == R_X86_64_64) {
|
|
LogMan::Msg::DFmt("\tR_X86_64_64");
|
|
}
|
|
else if (Type == R_X86_64_RELATIVE) {
|
|
LogMan::Msg::DFmt("\tR_X86_64_RELATIVE");
|
|
}
|
|
else if (Type == R_X86_64_GLOB_DAT) {
|
|
LogMan::Msg::DFmt("\tR_X86_64_GLOB_DAT");
|
|
}
|
|
else if (Type == R_X86_64_JUMP_SLOT) {
|
|
LogMan::Msg::DFmt("\tR_X86_64_JUMP_SLOT");
|
|
}
|
|
else if (Type == R_X86_64_DTPMOD64) {
|
|
LogMan::Msg::DFmt("\tR_X86_64_DTPMOD64");
|
|
}
|
|
else if (Type == R_X86_64_DTPOFF64) {
|
|
LogMan::Msg::DFmt("\tR_X86_64_DTPOFF64");
|
|
}
|
|
else if (Type == R_X86_64_TPOFF64) {
|
|
LogMan::Msg::DFmt("\tR_X86_64_TPOFF64");
|
|
}
|
|
else {
|
|
LogMan::Msg::DFmt("Unknown relocation type: {}(0x{:x})", Type, Type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, SymbolGetter Getter) {
|
|
if (Mode == MODE_32BIT) {
|
|
}
|
|
else {
|
|
Elf64_Shdr const *RelaHeader{nullptr};
|
|
Elf64_Shdr const *DynSymHeader {nullptr};
|
|
|
|
Elf64_Shdr const *StringTableHeader{nullptr};
|
|
char const *StrTab{nullptr};
|
|
|
|
for (size_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
const auto *hdr = SectionHeaders[i]._64;
|
|
if (hdr->sh_type == SHT_REL) {
|
|
LogMan::Msg::DFmt("Unhandled REL section");
|
|
}
|
|
else if (hdr->sh_type == SHT_RELA) {
|
|
RelaHeader = hdr;
|
|
|
|
if (RelaHeader->sh_info != 0) {
|
|
LOGMAN_THROW_A_FMT(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
|
|
}
|
|
|
|
if (RelaHeader->sh_link != 0) {
|
|
LOGMAN_THROW_A_FMT(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
|
|
DynSymHeader = SectionHeaders.at(RelaHeader->sh_link)._64;
|
|
|
|
StringTableHeader = SectionHeaders.at(DynSymHeader->sh_link)._64;
|
|
StrTab = &RawFile.at(StringTableHeader->sh_offset);
|
|
}
|
|
|
|
const size_t EntryCount = RelaHeader->sh_size / RelaHeader->sh_entsize;
|
|
const auto *Entries = reinterpret_cast<const Elf64_Rela *>(&RawFile.at(RelaHeader->sh_offset));
|
|
|
|
for (size_t j = 0; j < EntryCount; ++j) {
|
|
const auto *Entry = &Entries[j];
|
|
const uint32_t Sym = Entry->r_info >> 32;
|
|
const uint32_t Type = Entry->r_info & ~0U;
|
|
const Elf64_Sym *EntrySymbol{nullptr};
|
|
const char *EntrySymbolName{nullptr};
|
|
if (DynSymHeader && Sym != 0) {
|
|
LOGMAN_THROW_AA_FMT(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
|
|
|
|
const uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize;
|
|
EntrySymbol = reinterpret_cast<const Elf64_Sym *>(&RawFile.at(offset));
|
|
EntrySymbolName = &StrTab[EntrySymbol->st_name];
|
|
}
|
|
|
|
if (Type == R_X86_64_IRELATIVE) { // 37/0x25
|
|
// Indirect (B + A)
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
*Location = GuestELFBase + Entry->r_addend;
|
|
}
|
|
else if (Type == R_X86_64_64) {
|
|
// S + A
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
if (EntrySymbol != nullptr) {
|
|
auto ELFSym = Getter(EntrySymbolName, 0);
|
|
if (ELFSym != nullptr) {
|
|
*Location = ELFSym->Address + Entry->r_addend;
|
|
}
|
|
else {
|
|
*Location = 0xDEADBEEFBAD0DAD2ULL;
|
|
}
|
|
}
|
|
else {
|
|
*Location = 0xDEADBEEFBAD0DAD2ULL;
|
|
}
|
|
}
|
|
else if (Type == R_X86_64_RELATIVE) {
|
|
// B + A
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
*Location = GuestELFBase + Entry->r_addend;
|
|
}
|
|
else if (Type == R_X86_64_GLOB_DAT) {
|
|
// XXX: This is way wrong
|
|
// S
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
if (EntrySymbol != nullptr) {
|
|
auto ELFSym = Getter(EntrySymbolName, 2); // Leave out Symbols from the main executable and only grab non-weak
|
|
|
|
if (!ELFSym) {
|
|
ELFSym = Getter(EntrySymbolName, 0);
|
|
}
|
|
if (!ELFSym) {
|
|
ELFSym = Getter(EntrySymbolName, 3);
|
|
}
|
|
|
|
if (ELFSym != nullptr) {
|
|
*Location = ELFSym->Address;
|
|
}
|
|
else {
|
|
// XXX: This seems to be a loader edge case that if the symbol doesn't exist
|
|
// and it is a weakly defined GLOB_DAT type then it is allowed to continue?
|
|
// If we set Location to a value then apps crash
|
|
}
|
|
}
|
|
else {
|
|
*Location = 0xDEADBEEFBAD0DAD1ULL;
|
|
}
|
|
}
|
|
else if (Type == R_X86_64_JUMP_SLOT) {
|
|
// S
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
if (EntrySymbol != nullptr) {
|
|
auto ELFSym = Getter(EntrySymbolName, 0);
|
|
if (!ELFSym) { // XXX: Try again
|
|
ELFSym = Getter(EntrySymbolName, 3);
|
|
}
|
|
|
|
if (ELFSym != nullptr) {
|
|
*Location = ELFSym->Address;
|
|
}
|
|
else {
|
|
// XXX: This seems to be a loader edge case that if the symbol doesn't exist
|
|
// and it is a weakly defined GLOB_DAT type then it is allowed to continue?
|
|
*Location = 0xDEADBEEFBAD0DAD5ULL;
|
|
}
|
|
}
|
|
else {
|
|
*Location = 0xDEADBEEFBAD0DAD4ULL;
|
|
}
|
|
}
|
|
else if (Type == R_X86_64_DTPMOD64) {
|
|
// XXX: This is supposed to be the ID of the module that the symbol comes from for TLS purposes?
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
*Location = 0;
|
|
}
|
|
else if (Type == R_X86_64_DTPOFF64) {
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
if (EntrySymbol != nullptr) {
|
|
*Location = EntrySymbol->st_value + Entry->r_addend;
|
|
}
|
|
else {
|
|
*Location = 0xDEADBEEFBAD0DAD6ULL;
|
|
}
|
|
}
|
|
else if (Type == R_X86_64_TPOFF64) {
|
|
uint64_t *Location = reinterpret_cast<uint64_t*>(reinterpret_cast<uintptr_t>(ELFBase) + Entry->r_offset);
|
|
if (EntrySymbol != nullptr) {
|
|
// XXX: This is supposed to be a symbol with a TLS offset?
|
|
*Location = EntrySymbol->st_value + Entry->r_addend;
|
|
}
|
|
else {
|
|
// If we set Location to a value then apps crash
|
|
// *Location = 0xDEADBEEFBAD0DAD3ULL;
|
|
LogMan::Msg::DFmt("TPOFF without Entry? {:x} + {:x} + {:x}", GuestELFBase, TLSHeader._64->p_paddr, Entry->r_addend);
|
|
if (1) {
|
|
*Location = TLSHeader._64->p_paddr + Entry->r_addend;
|
|
}
|
|
else if (Entry->r_offset == 0x1e3dc8) {
|
|
*Location = 0xDEADBEEFBAD0DAD8ULL;
|
|
}
|
|
else {
|
|
*Location = Entry->r_addend - 0xb00'0;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LogMan::Msg::DFmt("Unknown relocation type: {}(0x{:x})", Type, Type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::PrintInitArray() const {
|
|
if (Mode == MODE_32BIT) {
|
|
for (size_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
const auto *hdr = SectionHeaders[i]._32;
|
|
if (hdr->sh_type == SHT_INIT_ARRAY) {
|
|
const size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; j < Entries; ++j) {
|
|
LogMan::Msg::DFmt("init_array[{}]", j);
|
|
LogMan::Msg::DFmt("\t{}", *reinterpret_cast<uint64_t const*>(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (size_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
const auto *hdr = SectionHeaders[i]._64;
|
|
if (hdr->sh_type == SHT_INIT_ARRAY) {
|
|
const size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; j < Entries; ++j) {
|
|
LogMan::Msg::DFmt("init_array[{}]", j);
|
|
LogMan::Msg::DFmt("\t{}", *reinterpret_cast<uint64_t const*>(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::PrintDynamicTable() const {
|
|
if (Mode == MODE_32BIT) {
|
|
for (size_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
const auto *hdr = SectionHeaders[i]._32;
|
|
if (hdr->sh_type == SHT_DYNAMIC) {
|
|
const auto *StrHeader = SectionHeaders.at(hdr->sh_link)._32;
|
|
const char *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
|
|
const size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; i < Entries; ++j) {
|
|
const auto *Dynamic = reinterpret_cast<const Elf32_Dyn *>(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize));
|
|
#define PRINT(x, y, z) x (Dynamic->d_tag == DT_##y ) LogMan::Msg::DFmt("Dyn {}: (" #y ") 0x{:x}", j, Dynamic->d_un.z);
|
|
if (Dynamic->d_tag == DT_NULL) {
|
|
break;
|
|
}
|
|
else if (Dynamic->d_tag == DT_NEEDED) {
|
|
LogMan::Msg::DFmt("Dyn {}: (NEEDED) '{}'", j, &SHStrings[Dynamic->d_un.d_val]);
|
|
}
|
|
else if (Dynamic->d_tag == DT_SONAME) {
|
|
LogMan::Msg::DFmt("Dyn {}: (SONAME) '{}'", j, &SHStrings[Dynamic->d_un.d_val]);
|
|
}
|
|
PRINT(else if, HASH, d_val)
|
|
PRINT(else if, INIT, d_val)
|
|
PRINT(else if, FINI, d_val)
|
|
PRINT(else if, INIT_ARRAY, d_val)
|
|
PRINT(else if, INIT_ARRAYSZ, d_val)
|
|
PRINT(else if, FINI_ARRAY, d_val)
|
|
PRINT(else if, FINI_ARRAYSZ, d_val)
|
|
PRINT(else if, GNU_HASH, d_val)
|
|
PRINT(else if, STRTAB, d_val)
|
|
PRINT(else if, SYMTAB, d_val)
|
|
PRINT(else if, STRSZ, d_val)
|
|
PRINT(else if, SYMENT, d_val)
|
|
PRINT(else if, DEBUG, d_val)
|
|
PRINT(else if, PLTGOT, d_val)
|
|
PRINT(else if, PLTRELSZ, d_val)
|
|
PRINT(else if, PLTREL, d_val)
|
|
PRINT(else if, JMPREL, d_val)
|
|
PRINT(else if, RELA, d_val)
|
|
PRINT(else if, RELASZ, d_val)
|
|
PRINT(else if, RELAENT, d_val)
|
|
PRINT(else if, VERNEED, d_val)
|
|
PRINT(else if, VERNEEDNUM, d_val)
|
|
PRINT(else if, VERSYM, d_val)
|
|
else if (Dynamic->d_tag >= DT_LOOS && Dynamic->d_tag <= DT_HIOS) {
|
|
LogMan::Msg::DFmt("Dyn {}: (OSSpecific) 0x{:x}", j, Dynamic->d_tag);
|
|
}
|
|
else if (Dynamic->d_tag >= DT_LOPROC && Dynamic->d_tag <= DT_HIPROC) {
|
|
LogMan::Msg::DFmt("Dyn {}: (Proc-Specific) 0x{:x}", j, Dynamic->d_tag);
|
|
}
|
|
PRINT(else if, RELACOUNT, d_val)
|
|
PRINT(else if, RELCOUNT, d_val)
|
|
PRINT(else if, VERDEF, d_val)
|
|
PRINT(else if, VERDEFNUM, d_val)
|
|
PRINT(else if, FLAGS, d_val)
|
|
else
|
|
LogMan::Msg::DFmt("Unknown dynamic section: {}(0x{:x})", Dynamic->d_tag, Dynamic->d_tag);
|
|
#undef PRINT
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (size_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
const auto *hdr = SectionHeaders[i]._64;
|
|
if (hdr->sh_type == SHT_DYNAMIC) {
|
|
const auto *StrHeader = SectionHeaders.at(hdr->sh_link)._64;
|
|
const char *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
|
|
|
const size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; i < Entries; ++j) {
|
|
const auto *Dynamic = reinterpret_cast<const Elf64_Dyn *>(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize));
|
|
#define PRINT(x, y, z) x (Dynamic->d_tag == DT_##y ) LogMan::Msg::DFmt("Dyn {}: (" #y ") 0x{:x}", j, Dynamic->d_un.z);
|
|
if (Dynamic->d_tag == DT_NULL) {
|
|
break;
|
|
}
|
|
else if (Dynamic->d_tag == DT_NEEDED) {
|
|
LogMan::Msg::DFmt("Dyn {}: (NEEDED) '{}'", j, &SHStrings[Dynamic->d_un.d_val]);
|
|
}
|
|
else if (Dynamic->d_tag == DT_SONAME) {
|
|
LogMan::Msg::DFmt("Dyn {}: (SONAME) '{}'", j, &SHStrings[Dynamic->d_un.d_val]);
|
|
}
|
|
PRINT(else if, HASH, d_val)
|
|
PRINT(else if, INIT, d_val)
|
|
PRINT(else if, FINI, d_val)
|
|
PRINT(else if, INIT_ARRAY, d_val)
|
|
PRINT(else if, INIT_ARRAYSZ, d_val)
|
|
PRINT(else if, FINI_ARRAY, d_val)
|
|
PRINT(else if, FINI_ARRAYSZ, d_val)
|
|
PRINT(else if, GNU_HASH, d_val)
|
|
PRINT(else if, STRTAB, d_val)
|
|
PRINT(else if, SYMTAB, d_val)
|
|
PRINT(else if, STRSZ, d_val)
|
|
PRINT(else if, SYMENT, d_val)
|
|
PRINT(else if, DEBUG, d_val)
|
|
PRINT(else if, PLTGOT, d_val)
|
|
PRINT(else if, PLTRELSZ, d_val)
|
|
PRINT(else if, PLTREL, d_val)
|
|
PRINT(else if, JMPREL, d_val)
|
|
PRINT(else if, RELA, d_val)
|
|
PRINT(else if, RELASZ, d_val)
|
|
PRINT(else if, RELAENT, d_val)
|
|
PRINT(else if, VERNEED, d_val)
|
|
PRINT(else if, VERNEEDNUM, d_val)
|
|
PRINT(else if, VERSYM, d_val)
|
|
else if (Dynamic->d_tag >= DT_LOOS && Dynamic->d_tag <= DT_HIOS) {
|
|
LogMan::Msg::DFmt("Dyn {}: (OSSpecific) 0x{:x}", j, Dynamic->d_tag);
|
|
}
|
|
else if (Dynamic->d_tag >= DT_LOPROC && Dynamic->d_tag <= DT_HIPROC) {
|
|
LogMan::Msg::DFmt("Dyn {}: (Proc-Specific) 0x{:x}", j, Dynamic->d_tag);
|
|
}
|
|
PRINT(else if, RELACOUNT, d_val)
|
|
PRINT(else if, RELCOUNT, d_val)
|
|
PRINT(else if, VERDEF, d_val)
|
|
PRINT(else if, VERDEFNUM, d_val)
|
|
PRINT(else if, FLAGS, d_val)
|
|
else
|
|
LogMan::Msg::DFmt("Unknown dynamic section: {}(0x{:x})", Dynamic->d_tag, Dynamic->d_tag);
|
|
#undef PRINT
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ELFContainer::GetInitLocations(uint64_t GuestELFBase, std::vector<uint64_t> *Locations) {
|
|
if (Mode == MODE_32BIT) {
|
|
// If INIT exists then add that first
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
|
if (hdr->sh_type == SHT_DYNAMIC) {
|
|
size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; i < Entries; ++j) {
|
|
Elf32_Dyn const *Dynamic = reinterpret_cast<Elf32_Dyn const*>(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize));
|
|
if (Dynamic->d_tag == DT_NULL) break;
|
|
if (Dynamic->d_tag == DT_INIT) {
|
|
Locations->emplace_back(GuestELFBase + Dynamic->d_un.d_val);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fill init_array
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
|
if (hdr->sh_type == SHT_INIT_ARRAY) {
|
|
size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; j < Entries; ++j) {
|
|
Locations->emplace_back(GuestELFBase + *reinterpret_cast<uint64_t const*>(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// If INIT exists then add that first
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (hdr->sh_type == SHT_DYNAMIC) {
|
|
size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; i < Entries; ++j) {
|
|
Elf64_Dyn const *Dynamic = reinterpret_cast<Elf64_Dyn const*>(&RawFile.at(hdr->sh_offset + j * hdr->sh_entsize));
|
|
if (Dynamic->d_tag == DT_NULL) break;
|
|
if (Dynamic->d_tag == DT_INIT) {
|
|
Locations->emplace_back(GuestELFBase + Dynamic->d_un.d_val);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fill init_array
|
|
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
|
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
|
if (hdr->sh_type == SHT_INIT_ARRAY) {
|
|
size_t Entries = hdr->sh_size / hdr->sh_entsize;
|
|
for (size_t j = 0; j < Entries; ++j) {
|
|
Locations->emplace_back(GuestELFBase + *reinterpret_cast<uint64_t const*>(&RawFile.at(hdr->sh_offset+ j * hdr->sh_entsize)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace ELFLoader
|