mirror of
https://github.com/Inori/GPCS4.git
synced 2024-06-02 19:38:19 -04:00
783 lines
17 KiB
C++
783 lines
17 KiB
C++
#include "ELFMapper.h"
|
|
|
|
#include "Emulator/ModuleSystemCommon.h"
|
|
#include "Platform.h"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
|
|
|
|
#ifdef MODSYS_DISABLE_MAPPER_LOG_DEBUG
|
|
|
|
#undef LOG_DEBUG
|
|
#define LOG_DEBUG(format, ...)
|
|
|
|
#endif // MODSYS_DISABLE_MAPPER_LOG_DEBUG
|
|
|
|
LOG_CHANNEL(Loader.ELFMapper);
|
|
|
|
bool ELFMapper::loadFile(std::string const &filePath, NativeModule *mod)
|
|
{
|
|
plat::file_uptr file = {};
|
|
bool retVal = false;
|
|
|
|
do
|
|
{
|
|
if (mod == nullptr)
|
|
{
|
|
LOG_ERR("Null module pointer");
|
|
break;
|
|
}
|
|
|
|
m_moduleData = mod;
|
|
|
|
if (!plat::LoadFile(filePath, mod->m_fileMemory))
|
|
{
|
|
LOG_ERR("failed to load file %s", filePath.c_str());
|
|
break;
|
|
}
|
|
|
|
retVal = true;
|
|
} while (false);
|
|
return retVal;
|
|
}
|
|
|
|
bool ELFMapper::validateHeader()
|
|
{
|
|
bool retVal = false;
|
|
|
|
do
|
|
{
|
|
if (m_moduleData == nullptr)
|
|
{
|
|
LOG_ERR("file has not been loaded");
|
|
break;
|
|
}
|
|
|
|
auto& fileMemory = m_moduleData->m_fileMemory;
|
|
|
|
if (fileMemory.size() < sizeof(*m_moduleData->m_elfHeader))
|
|
{
|
|
LOG_ERR("file size error. size=%d", fileMemory.size());
|
|
break;
|
|
}
|
|
|
|
m_moduleData->m_elfHeader = reinterpret_cast<Elf64_Ehdr *>(fileMemory.data());
|
|
auto elfHeader = m_moduleData->m_elfHeader;
|
|
|
|
if (strncmp((const char *)elfHeader->e_ident, ELFMAG, SELFMAG))
|
|
{
|
|
LOG_ERR("ELF identifier mismatch");
|
|
break;
|
|
}
|
|
|
|
if ((elfHeader->e_type != ET_SCE_DYNEXEC &&
|
|
elfHeader->e_type != ET_SCE_DYNAMIC) ||
|
|
elfHeader->e_machine != EM_X86_64)
|
|
{
|
|
LOG_ERR("unspported TYPE/ARCH. e_type=%d, e_machine=%d",
|
|
elfHeader->e_type, elfHeader->e_machine);
|
|
|
|
break;
|
|
}
|
|
|
|
retVal = true;
|
|
} while (false);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool ELFMapper::parseSegmentHeaders()
|
|
{
|
|
bool retVal = true;
|
|
|
|
do
|
|
{
|
|
if (m_moduleData == nullptr)
|
|
{
|
|
LOG_ERR("null pointer error");
|
|
retVal = false;
|
|
break;
|
|
}
|
|
|
|
auto& fileMemory = m_moduleData->m_fileMemory;
|
|
MODULE_INFO& info = m_moduleData->m_moduleInfo;
|
|
uint8_t* pSegmentHeader = fileMemory.data() + m_moduleData->m_elfHeader->e_phoff;
|
|
uint32_t shCount = m_moduleData->m_elfHeader->e_phnum;
|
|
|
|
m_moduleData->m_segmentHeaders.resize(shCount);
|
|
|
|
memcpy(m_moduleData->m_segmentHeaders.data(), pSegmentHeader,
|
|
shCount * sizeof(Elf64_Phdr));
|
|
|
|
uint8_t *pBuffer = fileMemory.data();
|
|
|
|
for (auto &hdr : m_moduleData->m_segmentHeaders)
|
|
{
|
|
switch (hdr.p_type)
|
|
{
|
|
case PT_LOAD:
|
|
case PT_INTERP:
|
|
case PT_GNU_EH_FRAME:
|
|
case PT_SCE_RELRO:
|
|
// TODO: what is PT_SCE_MODULEPARAM used for?
|
|
case PT_SCE_MODULEPARAM:
|
|
break;
|
|
|
|
case PT_SCE_PROCPARAM:
|
|
{
|
|
info.pProcParam = reinterpret_cast<void *>(hdr.p_vaddr);
|
|
break;
|
|
}
|
|
|
|
case PT_DYNAMIC:
|
|
{
|
|
info.pDynamic = pBuffer + hdr.p_offset;
|
|
info.nDynamicSize = hdr.p_filesz;
|
|
}
|
|
break;
|
|
|
|
case PT_TLS:
|
|
{
|
|
info.pTlsAddr = reinterpret_cast<uint8_t *>(hdr.p_vaddr);
|
|
info.nTlsInitSize = hdr.p_filesz;
|
|
info.nTlsSize = util::align(hdr.p_memsz, hdr.p_align);
|
|
info.nTlsAlign = hdr.p_align;
|
|
}
|
|
break;
|
|
|
|
case PT_SCE_DYNLIBDATA:
|
|
{
|
|
info.pSceDynLib = pBuffer + hdr.p_offset;
|
|
info.nSceDynLibSize = hdr.p_filesz;
|
|
}
|
|
break;
|
|
|
|
case PT_SCE_COMMENT:
|
|
{
|
|
info.pSceComment = pBuffer + hdr.p_offset;
|
|
info.nSceCommentSize = hdr.p_filesz;
|
|
}
|
|
break;
|
|
|
|
case PT_SCE_LIBVERSION:
|
|
{
|
|
info.pSceLibVersion = pBuffer + hdr.p_offset;
|
|
info.nSceLibVersionSize = hdr.p_filesz;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
LOG_FIXME("segment type: %x is not supported", hdr.p_type);
|
|
retVal = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool ELFMapper::parseDynamicSection()
|
|
{
|
|
assert(m_moduleData != nullptr);
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
|
|
bool retVal = false;
|
|
|
|
do
|
|
{
|
|
Elf64_Dyn *pDynEntries = reinterpret_cast<Elf64_Dyn *>(info.pDynamic);
|
|
uint32_t dynEntriesCount = info.nDynamicSize / sizeof(Elf64_Dyn);
|
|
uint8_t *pStrTab = info.pStrTab;
|
|
|
|
for (uint32_t i = 0; i < dynEntriesCount; i++)
|
|
{
|
|
retVal = prepareTables(pDynEntries[i], i);
|
|
if (retVal == false)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (retVal == false)
|
|
{
|
|
break;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < dynEntriesCount; i++)
|
|
{
|
|
retVal = parseSingleDynEntry(pDynEntries[i], i);
|
|
if (retVal == false)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while (false);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void *ELFMapper::getProcParam() const
|
|
{
|
|
const auto &info = m_moduleData->m_moduleInfo;
|
|
return info.pProcParam;
|
|
}
|
|
|
|
bool ELFMapper::mapImageIntoMemory()
|
|
{
|
|
bool retVal = false;
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
|
|
do
|
|
{
|
|
size_t totalSize = calculateTotalLoadableSize();
|
|
if (totalSize == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
uint8_t* buffer = reinterpret_cast<uint8_t*>(plat::VMAllocateAlign(
|
|
nullptr,
|
|
totalSize, plat::VM_PAGE_SIZE,
|
|
plat::VMAT_RESERVE_COMMIT, plat::VMPF_CPU_RWX));
|
|
|
|
if (buffer == nullptr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
m_moduleData->m_mappedMemory.reset(buffer);
|
|
m_moduleData->m_mappedSize = totalSize;
|
|
|
|
LOG_DEBUG("Module %s loaded. start %p end %p size=%ld",
|
|
m_moduleData->fileName.c_str(), buffer, buffer + totalSize, totalSize);
|
|
|
|
info.pMappedAddr = buffer;
|
|
info.nMappedSize = totalSize;
|
|
|
|
for (auto const &phdr : m_moduleData->m_segmentHeaders)
|
|
{
|
|
if (phdr.p_flags & PF_X)
|
|
{
|
|
retVal = mapCodeSegment(phdr);
|
|
LOG_DEBUG("code segment at 0x%x size=%ld", info.pCodeAddr,
|
|
info.nCodeSize);
|
|
}
|
|
else if (phdr.p_type == PT_SCE_RELRO)
|
|
{
|
|
retVal = mapSecReloSegment(phdr);
|
|
}
|
|
else if (phdr.p_flags & PF_W)
|
|
{
|
|
retVal = mapDataSegment(phdr);
|
|
LOG_DEBUG("data segment at 0x%x size=%ld", info.pDataAddr,
|
|
info.nDataSize);
|
|
// there should no longer be segment to be mapped,
|
|
// and we stop enumerating right here.
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while (false);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// TODO: clean up the verbose code here when it is done.
|
|
bool ELFMapper::parseSymbols()
|
|
{
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
auto pSymbolTable = (Elf64_Sym *)info.pSymTab;
|
|
auto tableSize = info.nSymTabSize / sizeof(Elf64_Sym);
|
|
|
|
for (uint32_t i = 0; i < tableSize; i++)
|
|
{
|
|
auto const &symbol = reinterpret_cast<Elf64_Sym *>(info.pSymTab)[i];
|
|
auto binding = ELF64_ST_BIND(symbol.st_info);
|
|
auto name = (char *)(&info.pStrTab[symbol.st_name]);
|
|
auto isDef = symbol.st_value == 0 ? "UNDEF" : "EXPORT";
|
|
SymbolInfo si = {};
|
|
|
|
si.type = static_cast<SymbolInfo::Type>(ELF64_ST_TYPE(symbol.st_info));
|
|
si.symbolName = name;
|
|
si.isEncoded = m_moduleData->isEncodedSymbol(name);
|
|
|
|
switch (binding)
|
|
{
|
|
case STB_LOCAL:
|
|
{
|
|
//LOG_DEBUG("%s symbol: %s BINDING: STB_LOCAL VAL: %d", isDef, name,
|
|
// symbol.st_value);
|
|
void *addr = m_moduleData->m_mappedMemory.get() + symbol.st_value;
|
|
|
|
si.binding = SymbolInfo::Binding::LOCAL;
|
|
si.address = reinterpret_cast<uint64_t>(addr);
|
|
m_moduleData->m_symbols.emplace_back(si);
|
|
}
|
|
break;
|
|
|
|
case STB_GLOBAL:
|
|
{
|
|
//LOG_DEBUG("%s symbol: %s BINDING: STB_GLOBAL VAL: %d", isDef, name,
|
|
// symbol.st_value);
|
|
|
|
si.binding = SymbolInfo::Binding::GLOBAL;
|
|
void *addr = nullptr;
|
|
|
|
if (symbol.st_value != 0)
|
|
{
|
|
addr = m_moduleData->m_mappedMemory.get() + symbol.st_value;
|
|
auto ret = m_moduleData->getExportSymbolInfo(
|
|
name, &si.moduleName, &si.libraryName, &si.nid);
|
|
if (ret != true)
|
|
{
|
|
LOG_ERR("fail to find information for symbol %s", name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto ret = m_moduleData->getImportSymbolInfo(
|
|
name, &si.moduleName, &si.libraryName, &si.nid);
|
|
if (ret != true)
|
|
{
|
|
LOG_ERR("fail to find information for symbol %s", name);
|
|
}
|
|
}
|
|
si.address = reinterpret_cast<uint64_t>(addr);
|
|
auto idx = m_moduleData->m_symbols.size();
|
|
m_moduleData->m_symbols.emplace_back(si);
|
|
m_moduleData->m_nameSymbolMap.insert(std::make_pair(name, idx));
|
|
if (symbol.st_value != 0)
|
|
{
|
|
m_moduleData->m_exportSymbols.push_back(idx);
|
|
}
|
|
else
|
|
{
|
|
m_moduleData->m_importSymbols.push_back(idx);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// TODO: merge this branch with STB_GLOBAL
|
|
case STB_WEAK:
|
|
{
|
|
//LOG_DEBUG("%s symbol: %s BINDING: STB_WEAK VAL: %d", isDef, name,
|
|
// symbol.st_value);
|
|
|
|
si.binding = SymbolInfo::Binding::WEAK;
|
|
void *addr = nullptr;
|
|
|
|
if (symbol.st_value != 0)
|
|
{
|
|
addr = m_moduleData->m_mappedMemory.get() + symbol.st_value;
|
|
|
|
auto ret = m_moduleData->getExportSymbolInfo(
|
|
name, &si.moduleName, &si.libraryName, &si.nid);
|
|
if (ret != true)
|
|
{
|
|
LOG_ERR("fail to find information for symbol %s", name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto ret = m_moduleData->getImportSymbolInfo(
|
|
name, &si.moduleName, &si.libraryName, &si.nid);
|
|
if (!ret)
|
|
{
|
|
LOG_ERR("fail to find information for symbol %s", name);
|
|
}
|
|
}
|
|
si.address = reinterpret_cast<uint64_t>(addr);
|
|
auto idx = m_moduleData->m_symbols.size();
|
|
m_moduleData->m_symbols.emplace_back(si);
|
|
m_moduleData->m_nameSymbolMap.insert(std::make_pair(name, idx));
|
|
if (symbol.st_value != 0)
|
|
{
|
|
m_moduleData->m_exportSymbols.push_back(idx);
|
|
}
|
|
else
|
|
{
|
|
m_moduleData->m_importSymbols.push_back(idx);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ELFMapper::prepareTables(Elf64_Dyn const &entry, uint32_t index)
|
|
{
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
uint8_t *pDynBaseAddr = info.pSceDynLib;
|
|
bool retVal = true;
|
|
|
|
switch (entry.d_tag)
|
|
{
|
|
case DT_NULL:
|
|
case DT_NEEDED:
|
|
case DT_DEBUG:
|
|
case DT_TEXTREL:
|
|
case DT_INIT_ARRAY:
|
|
case DT_FINI_ARRAY:
|
|
case DT_INIT_ARRAYSZ:
|
|
case DT_FINI_ARRAYSZ:
|
|
case DT_FLAGS:
|
|
case DT_PREINIT_ARRAY:
|
|
case DT_PREINIT_ARRAYSZ:
|
|
case DT_SCE_FINGERPRINT:
|
|
case DT_SCE_ORIGINAL_FILENAME:
|
|
case DT_SCE_MODULE_INFO:
|
|
case DT_SCE_NEEDED_MODULE:
|
|
case DT_SCE_MODULE_ATTR:
|
|
case DT_SCE_EXPORT_LIB:
|
|
case DT_SCE_IMPORT_LIB:
|
|
case DT_SCE_EXPORT_LIB_ATTR:
|
|
case DT_SCE_IMPORT_LIB_ATTR:
|
|
case DT_SCE_RELAENT:
|
|
case DT_SCE_SYMENT:
|
|
case DT_SCE_HASH:
|
|
case DT_SCE_HASHSZ:
|
|
case DT_SONAME:
|
|
break;
|
|
|
|
case DT_INIT:
|
|
{
|
|
LOG_DEBUG("INIT addr: %x", entry.d_un.d_ptr);
|
|
info.pInitProc = reinterpret_cast<void *>(entry.d_un.d_ptr);
|
|
}
|
|
break;
|
|
|
|
case DT_FINI:
|
|
{
|
|
LOG_DEBUG("FINI addr: %x", entry.d_un.d_ptr);
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_PLTGOT:
|
|
{
|
|
LOG_DEBUG("PLTGOT addr: %x", entry.d_un.d_ptr);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
symbol table
|
|
|
|
Is it possible for a elf file to have multiple symbol tables?
|
|
*/
|
|
case DT_SCE_SYMTAB:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_SYMTAB",
|
|
entry.d_un.d_val);
|
|
|
|
// I'm not sure if it is possible for a ELF file to have multiple symbol
|
|
// tables. I simply assume there could only be one, and therefore before
|
|
// it is being set, the value of the symobl table pointer should be
|
|
// null.
|
|
assert(info.pSymTab == nullptr);
|
|
info.pSymTab = pDynBaseAddr + entry.d_un.d_ptr;
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_SYMTABSZ:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_SYMTABSZ",
|
|
entry.d_un.d_val);
|
|
assert(info.nSymTabSize == 0);
|
|
info.nSymTabSize = entry.d_un.d_val;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
string table
|
|
*/
|
|
case DT_SCE_STRTAB:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_STRTAB",
|
|
entry.d_un.d_val);
|
|
assert(info.pStrTab == nullptr);
|
|
info.pStrTab = pDynBaseAddr + entry.d_un.d_ptr;
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_STRSZ:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_STRSZ",
|
|
entry.d_un.d_val);
|
|
assert(info.nStrTabSize == 0);
|
|
info.nStrTabSize = entry.d_un.d_val;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
Relocation table
|
|
*/
|
|
case DT_SCE_RELA:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_RELA",
|
|
entry.d_un.d_val);
|
|
assert(info.pRela == nullptr);
|
|
info.pRela = pDynBaseAddr + entry.d_un.d_ptr;
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_RELASZ:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_RELASZ",
|
|
entry.d_un.d_val);
|
|
assert(info.nRelaCount == 0);
|
|
info.nRelaCount = entry.d_un.d_val / sizeof(Elf64_Rela);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
PLT relocation table
|
|
*/
|
|
case DT_SCE_JMPREL:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_JMPREL",
|
|
entry.d_un.d_val);
|
|
assert(info.pPltRela == nullptr);
|
|
info.pPltRela = pDynBaseAddr + entry.d_un.d_ptr;
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_PLTREL:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_PLTREL",
|
|
entry.d_un.d_val);
|
|
assert(info.nPltRelType == 0);
|
|
info.nPltRelType = entry.d_un.d_val;
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_PLTRELSZ:
|
|
{
|
|
LOG_DEBUG(" %i: d_tag = %s, d_un = %08x", index, "DT_SCE_PLTRELSZ",
|
|
entry.d_un.d_val);
|
|
assert(info.nPltRelaCount == 0);
|
|
info.nPltRelaCount = entry.d_un.d_val / sizeof(Elf64_Rela);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
LOG_FIXME(" %i UNKNOWN DTAG: 0x%08x", index, entry.d_tag);
|
|
retVal = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool ELFMapper::parseSingleDynEntry(Elf64_Dyn const &entry, uint32_t index)
|
|
{
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
uint8_t *strTable = info.pStrTab;
|
|
|
|
switch (entry.d_tag)
|
|
{
|
|
case DT_NEEDED:
|
|
{
|
|
char *fileName = (char *)&strTable[entry.d_un.d_ptr];
|
|
m_moduleData->m_neededFiles.push_back(fileName);
|
|
LOG_DEBUG("DT_NEEDED: %s", fileName);
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_MODULE_INFO:
|
|
{
|
|
IMPORT_MODULE mod;
|
|
mod.value = entry.d_un.d_val;
|
|
mod.strName = reinterpret_cast<char *>(&strTable[mod.name_offset]);
|
|
m_moduleData->m_exportModules.push_back(mod);
|
|
LOG_DEBUG("DT_SCE_MODULE_INFO: %s", mod.strName.c_str());
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_NEEDED_MODULE:
|
|
{
|
|
IMPORT_MODULE mod;
|
|
mod.value = entry.d_un.d_val;
|
|
mod.strName = reinterpret_cast<char *>(&strTable[mod.name_offset]);
|
|
m_moduleData->m_importModules.push_back(mod);
|
|
LOG_DEBUG("DT_SCE_NEEDED_MODULE: %s", mod.strName.c_str());
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_EXPORT_LIB:
|
|
{
|
|
IMPORT_LIBRARY lib;
|
|
lib.value = entry.d_un.d_val;
|
|
lib.strName = reinterpret_cast<char *>(&strTable[lib.name_offset]);
|
|
m_moduleData->m_exportLibraries.push_back(lib);
|
|
LOG_DEBUG("DT_SCE_EXPORT_LIB %s", lib.strName.c_str());
|
|
}
|
|
break;
|
|
|
|
case DT_SCE_IMPORT_LIB:
|
|
{
|
|
IMPORT_LIBRARY lib;
|
|
lib.value = entry.d_un.d_val;
|
|
lib.strName = reinterpret_cast<char *>(&strTable[lib.name_offset]);
|
|
m_moduleData->m_importLibraries.push_back(lib);
|
|
LOG_DEBUG("DT_SCE_IMPORT_LIB %s", lib.strName.c_str());
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t ELFMapper::calculateTotalLoadableSize()
|
|
{
|
|
size_t loadAddrBegin = 0;
|
|
size_t loadAddrEnd = 0;
|
|
|
|
for (auto &phdr : m_moduleData->m_segmentHeaders)
|
|
{
|
|
if (isSegmentLoadable(phdr))
|
|
{
|
|
if (phdr.p_vaddr < loadAddrBegin)
|
|
{
|
|
loadAddrBegin = phdr.p_vaddr;
|
|
}
|
|
|
|
size_t alignedAddr =
|
|
util::alignDown(phdr.p_vaddr + phdr.p_memsz, phdr.p_align);
|
|
if (alignedAddr > loadAddrEnd)
|
|
{
|
|
loadAddrEnd = alignedAddr;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (loadAddrEnd - loadAddrBegin);
|
|
}
|
|
|
|
bool ELFMapper::isSegmentLoadable(Elf64_Phdr const &hdr)
|
|
{
|
|
bool retVal;
|
|
|
|
if (hdr.p_type == PT_SCE_RELRO)
|
|
{
|
|
retVal = true;
|
|
}
|
|
else if (hdr.p_type == PT_LOAD)
|
|
{
|
|
retVal = true;
|
|
}
|
|
else
|
|
{
|
|
retVal = false;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool ELFMapper::mapCodeSegment(Elf64_Phdr const &phdr)
|
|
{
|
|
bool retVal = false;
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
auto &fileData = m_moduleData->m_fileMemory;
|
|
do
|
|
{
|
|
if (fileData.empty())
|
|
{
|
|
break;
|
|
}
|
|
|
|
info.nCodeSize = phdr.p_memsz;
|
|
info.pCodeAddr = reinterpret_cast<uint8_t*>(
|
|
util::alignDown(size_t(info.pMappedAddr + phdr.p_vaddr), phdr.p_align));
|
|
|
|
uint8_t *fileDataPtr = fileData.data() + phdr.p_offset;
|
|
|
|
memcpy(info.pCodeAddr, fileDataPtr, phdr.p_filesz);
|
|
if (m_moduleData->m_elfHeader->e_entry != 0)
|
|
{
|
|
//info.pEntryPoint = info.pCodeAddr + m_moduleData->elfHeader->e_entry;
|
|
info.pEntryPoint = info.pMappedAddr + m_moduleData->m_elfHeader->e_entry;
|
|
}
|
|
else
|
|
{
|
|
info.pEntryPoint = nullptr;
|
|
}
|
|
|
|
info.pInitProc = reinterpret_cast<uint64_t>(info.pInitProc) + info.pMappedAddr;
|
|
|
|
if (info.pTlsAddr != nullptr)
|
|
{
|
|
info.pTlsAddr = info.pCodeAddr + (uint64_t)info.pTlsAddr;
|
|
}
|
|
|
|
retVal = true;
|
|
|
|
} while (false);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool ELFMapper::mapSecReloSegment(Elf64_Phdr const &phdr)
|
|
{
|
|
bool retVal = false;
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
auto &fileData = m_moduleData->m_fileMemory;
|
|
|
|
do
|
|
{
|
|
if (fileData.empty())
|
|
{
|
|
break;
|
|
}
|
|
|
|
uint8_t *relroAddr = reinterpret_cast<uint8_t *>(
|
|
util::alignDown(size_t(info.pMappedAddr + phdr.p_vaddr), phdr.p_align));
|
|
uint8_t *fileDataPtr = fileData.data() + phdr.p_offset;
|
|
|
|
memcpy(relroAddr, fileDataPtr, phdr.p_filesz);
|
|
retVal = true;
|
|
|
|
} while (false);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool ELFMapper::mapDataSegment(Elf64_Phdr const &phdr)
|
|
{
|
|
bool retVal = false;
|
|
MODULE_INFO &info = m_moduleData->m_moduleInfo;
|
|
auto &fileData = m_moduleData->m_fileMemory;
|
|
|
|
do
|
|
{
|
|
if (fileData.empty())
|
|
{
|
|
break;
|
|
}
|
|
|
|
info.nDataSize = phdr.p_memsz;
|
|
info.pDataAddr = reinterpret_cast<uint8_t *>(
|
|
util::alignDown(size_t(info.pMappedAddr) + phdr.p_vaddr, phdr.p_align));
|
|
|
|
uint8_t *fileDataPtr = fileData.data() + phdr.p_offset;
|
|
memcpy(info.pDataAddr, fileDataPtr, phdr.p_filesz);
|
|
|
|
if (info.pProcParam != nullptr)
|
|
{
|
|
info.pProcParam = info.pMappedAddr + reinterpret_cast<uint64_t>(info.pProcParam);
|
|
}
|
|
|
|
retVal = true;
|
|
|
|
} while (false);
|
|
|
|
return retVal;
|
|
}
|