mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 10:00:16 +02:00
FEXOfflineCompiler: Apply relocations to loaded ELF binaries
This commit is contained in:
1 parent
152fe81d16
commit
293568be36
2 files changed
+85
-8
No files matched your search
@@ -304,6 +304,56 @@ struct ELFParser {
|
||||
return Relocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns underlying 32-bit relocation entries.
|
||||
* SHT_REL entries are implicitly converted to Elf32_Rela.
|
||||
*/
|
||||
fextl::vector<Elf32_Rela> ReadRawRelocations32() {
|
||||
if (fd == -1 || type != ::ELFLoader::ELFContainer::TYPE_X86_32 || !EnsureSectionHeadersLoaded()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Load dynamic symbol table (find SHT_DYNSYM section)
|
||||
fextl::vector<Elf32_Sym> DynSyms;
|
||||
auto DynsymHeader = std::ranges::find_if(*shdrs, [](auto& shdr) { return shdr.sh_type == SHT_DYNSYM; });
|
||||
if (DynsymHeader != shdrs->end()) {
|
||||
size_t SymCount = DynsymHeader->sh_size / sizeof(Elf32_Sym);
|
||||
DynSyms.resize(SymCount);
|
||||
if (pread(fd, DynSyms.data(), DynsymHeader->sh_size, DynsymHeader->sh_offset) == -1) {
|
||||
LOGMAN_MSG_A_FMT("Could not load DYNSYM section");
|
||||
}
|
||||
}
|
||||
|
||||
fextl::vector<Elf32_Rela> Result;
|
||||
for (const auto& shdr : *shdrs) {
|
||||
if (shdr.sh_entsize == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t EntryCount = shdr.sh_size / shdr.sh_entsize;
|
||||
|
||||
if (shdr.sh_type == SHT_REL) {
|
||||
fextl::vector<Elf32_Rel> Entries(EntryCount);
|
||||
if (pread(fd, Entries.data(), shdr.sh_size, shdr.sh_offset) == -1) {
|
||||
LOGMAN_MSG_A_FMT("Could not load REL section");
|
||||
}
|
||||
for (auto& Entry : Entries) {
|
||||
auto Sym = ELF32_R_SYM(Entry.r_info);
|
||||
int32_t Addend = (Sym < DynSyms.size()) ? static_cast<int32_t>(DynSyms[Sym].st_value) : 0;
|
||||
Result.push_back(Elf32_Rela {Entry.r_offset, Entry.r_info, Addend});
|
||||
}
|
||||
} else if (shdr.sh_type == SHT_RELA) {
|
||||
fextl::vector<Elf32_Rela> Entries(EntryCount);
|
||||
if (pread(fd, Entries.data(), shdr.sh_size, shdr.sh_offset) == -1) {
|
||||
LOGMAN_MSG_A_FMT("Could not load RELA section");
|
||||
}
|
||||
Result.insert(Result.end(), Entries.begin(), Entries.end());
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void Closefd() {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
|
||||
@@ -50,7 +50,8 @@ public:
|
||||
}
|
||||
|
||||
void* GuestMmap(FEXCore::Core::InternalThreadState*, void* addr, size_t Size, int prot, int Flags, int fd, off_t offset) override {
|
||||
auto Ret = mmap(addr, Size, prot, Flags, fd, offset);
|
||||
// Force writeable to allow applying relocations
|
||||
auto Ret = mmap(addr, Size, prot | PROT_WRITE, Flags, fd, offset);
|
||||
if (Ret != MAP_FAILED && VAFileStart == 0) {
|
||||
VAFileStart = reinterpret_cast<uintptr_t>(Ret);
|
||||
}
|
||||
@@ -113,8 +114,7 @@ static FEXCore::Core::InternalThreadState* SetupCompileThread(FEXCore::Context::
|
||||
}
|
||||
|
||||
// Returns filename of generated cache on success
|
||||
static std::optional<std::string>
|
||||
GenerateSingleCache(const FEXCore::ExecutableFileInfo& Binary, fextl::set<uintptr_t> BlockList, std::string_view OutDir) {
|
||||
static std::optional<std::string> GenerateSingleCache(FEXCore::ExecutableFileInfo& Binary, fextl::set<uintptr_t> BlockList, std::string_view OutDir) {
|
||||
uint64_t CodeCacheConfigId = 0; // TODO: Make unique to active configuration
|
||||
|
||||
ELFCodeLoader Loader(Binary.Filename.c_str(), -1, "", fextl::vector<fextl::string> {Binary.Filename.c_str()},
|
||||
@@ -123,7 +123,19 @@ GenerateSingleCache(const FEXCore::ExecutableFileInfo& Binary, fextl::set<uintpt
|
||||
fmt::print("Invalid or unsupported ELF file.\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const bool Is64Bit = Loader.Is64BitMode();
|
||||
auto SyscallOSABI = Is64Bit ? FEXCore::HLE::SyscallOSABI::OS_LINUX64 : FEXCore::HLE::SyscallOSABI::OS_LINUX32;
|
||||
auto SyscallHandler = std::make_unique<AOTSyscallHandler>(SyscallOSABI);
|
||||
|
||||
// Populate relocations from ELF file
|
||||
{
|
||||
ELFParser RelocParser;
|
||||
RelocParser.ReadElf(Binary.Filename);
|
||||
Binary.Relocations = RelocParser.PopulateRelocations();
|
||||
SyscallHandler->FileInfo.Relocations = Binary.Relocations;
|
||||
}
|
||||
|
||||
FEXCore::Config::Set(FEXCore::Config::CONFIG_IS64BIT_MODE, Is64Bit ? "1" : "0");
|
||||
|
||||
// Load HostFeatures
|
||||
@@ -137,13 +149,9 @@ GenerateSingleCache(const FEXCore::ExecutableFileInfo& Binary, fextl::set<uintpt
|
||||
|
||||
auto CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures);
|
||||
|
||||
auto SignalDelegation = std::make_unique<FEX::DummyHandlers::DummySignalDelegator>();
|
||||
|
||||
auto SyscallOSABI = Is64Bit ? FEXCore::HLE::SyscallOSABI::OS_LINUX64 : FEXCore::HLE::SyscallOSABI::OS_LINUX32;
|
||||
auto SyscallHandler = std::make_unique<AOTSyscallHandler>(SyscallOSABI);
|
||||
|
||||
Loader.CalculateHWCaps(CTX.get());
|
||||
|
||||
auto SignalDelegation = std::make_unique<FEX::DummyHandlers::DummySignalDelegator>();
|
||||
CTX->SetSignalDelegator(SignalDelegation.get());
|
||||
CTX->SetSyscallHandler(SyscallHandler.get());
|
||||
auto ThunkHandler = FEX::HLE::CreateThunkHandler();
|
||||
@@ -166,6 +174,25 @@ GenerateSingleCache(const FEXCore::ExecutableFileInfo& Binary, fextl::set<uintpt
|
||||
if (!ElfBase.has_value()) {
|
||||
ERROR_AND_DIE_FMT("Failed to load ELF file {} ({})", Binary.Filename, Binary.FileId);
|
||||
}
|
||||
|
||||
{
|
||||
ELFParser RelocParser;
|
||||
RelocParser.ReadElf(Binary.Filename);
|
||||
auto relocs32 = RelocParser.ReadRawRelocations32();
|
||||
|
||||
for (auto& reloc : relocs32) {
|
||||
if (ELF32_R_TYPE(reloc.r_info) == R_386_RELATIVE) {
|
||||
// The FEX-relocation is applied on top of this during cache serialization, so this must be countered
|
||||
uint32_t val = *reinterpret_cast<uint32_t*>(SyscallHandler->VAFileStart + reloc.r_offset) + SyscallHandler->VAFileStart;
|
||||
memcpy(reinterpret_cast<uint32_t*>(SyscallHandler->VAFileStart + reloc.r_offset), &val, sizeof(val));
|
||||
} else if (ELF32_R_TYPE(reloc.r_info) == R_386_32) {
|
||||
// The FEX-relocation is applied on top of this during cache serialization, so this must be countered
|
||||
uint32_t* orig = reinterpret_cast<uint32_t*>(SyscallHandler->VAFileStart + reloc.r_offset);
|
||||
uint32_t val = *orig + reloc.r_addend + SyscallHandler->VAFileStart;
|
||||
memcpy(orig, &val, sizeof(val));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CTX->GetCodeCache().InitiateCacheGeneration();
|
||||
|
||||
Reference in new issue
Block a user