mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 13:00:15 +02:00
LinuxSyscalls: Enable delayed code cache load for ELF files
Specifically this is needed if any ELF relocations cover read-only code sections, which is indicated in the ELF headers via DT_TEXTREL/DF_TEXTREL.
This commit is contained in:
1 parent
226bd51afe
commit
1ea24f3d6c
2 files changed
+52
-1
No files matched your search
@@ -240,6 +240,54 @@ struct ELFParser {
|
||||
return ReadElf(NewFD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if DT_TEXTREL/DF_TEXTREL exist in the PT_DYNAMIC segment.
|
||||
*
|
||||
* These indicate that the ELF has relocations that cover to read-only code
|
||||
* pages. The dynamic loader will temporarily map these pages as writeable
|
||||
* to apply the relocations.
|
||||
*/
|
||||
bool HasCodeRelocations() const {
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto phdr_it = std::ranges::find_if(phdrs, [](auto& phdr) { return phdr.p_type == PT_DYNAMIC; });
|
||||
if (phdr_it == phdrs.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == ::ELFLoader::ELFContainer::TYPE_X86_32) {
|
||||
return HasCodeRelocations<Elf32_Dyn>(*phdr_it);
|
||||
} else {
|
||||
return HasCodeRelocations<Elf64_Dyn>(*phdr_it);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Elf_Dyn>
|
||||
bool HasCodeRelocations(const Elf64_Phdr& phdr) const {
|
||||
const size_t EntryCount = phdr.p_filesz / sizeof(Elf_Dyn);
|
||||
fextl::vector<Elf_Dyn> Entries(EntryCount);
|
||||
|
||||
if (pread(fd, Entries.data(), phdr.p_filesz, phdr.p_offset) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& Entry : Entries) {
|
||||
if (Entry.d_tag == DT_NULL) {
|
||||
break;
|
||||
}
|
||||
if (Entry.d_tag == DT_TEXTREL) {
|
||||
return true;
|
||||
}
|
||||
if (Entry.d_tag == DT_FLAGS && (Entry.d_un.d_val & DF_TEXTREL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses relocation sections (SHT_REL/SHT_RELA) and returns a map of
|
||||
* offsets to relocations that FEX's JIT must know about.
|
||||
|
||||
@@ -205,6 +205,7 @@ FEXCore::HLE::ExecutableRangeInfo SyscallHandler::QueryGuestExecutableRange(FEXC
|
||||
struct ReadELFHeadersResult {
|
||||
fextl::vector<Elf64_Phdr> ProgramHeaders;
|
||||
fextl::robin_map<uint32_t, FEXCore::GuestRelocationType> Relocations;
|
||||
bool HasCodeRelocations;
|
||||
};
|
||||
|
||||
static ReadELFHeadersResult ReadELFHeaders(int FD, std::span<std::byte> HeaderData = {}) {
|
||||
@@ -226,7 +227,8 @@ static ReadELFHeadersResult ReadELFHeaders(int FD, std::span<std::byte> HeaderDa
|
||||
LogMan::Msg::IFmt("Loaded ELF with {} relocations", Relocations.size());
|
||||
}
|
||||
|
||||
return ReadELFHeadersResult {std::move(Parser.phdrs), std::move(Relocations)};
|
||||
auto HasCodeRelocations = Parser.HasCodeRelocations();
|
||||
return ReadELFHeadersResult {std::move(Parser.phdrs), std::move(Relocations), HasCodeRelocations};
|
||||
}
|
||||
|
||||
static void LoadCodeCache(FEXCore::Core::InternalThreadState& Thread, FEXCore::ExecutableFileSectionInfo& Section, uint64_t CodeCacheConfigId) {
|
||||
@@ -552,6 +554,7 @@ SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState* Thread, uint64_t a
|
||||
auto ELFResult = ReadELFHeaders(fd, std::span {reinterpret_cast<std::byte*>(addr), length});
|
||||
Resource->ProgramHeaders = std::move(ELFResult.ProgramHeaders);
|
||||
Resource->MappedFile->Relocations = std::move(ELFResult.Relocations);
|
||||
Resource->RequiresDelayedCacheLoad = ELFResult.HasCodeRelocations;
|
||||
LOGMAN_THROW_A_FMT(Resource->ProgramHeaders.empty() || offset == 0, "Expected file offset 0 for the first mapping of an ELF "
|
||||
"file");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user