From 702d9819257e7af4d8c085fe30d37efe5bc2fedc Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Mon, 22 Dec 2025 15:27:07 +0000 Subject: [PATCH] ImageTracker: Load PE relocations when generating code caches --- Source/Windows/Common/ImageTracker.cpp | 48 ++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/Source/Windows/Common/ImageTracker.cpp b/Source/Windows/Common/ImageTracker.cpp index 8131ccbb8..0076b3b18 100644 --- a/Source/Windows/Common/ImageTracker.cpp +++ b/Source/Windows/Common/ImageTracker.cpp @@ -75,6 +75,43 @@ static void LoadImageVolatileMetadata(fextl::set& VolatileInstructions } } +static fextl::unordered_map LoadImageRelocations(ArchImageNtHeaders* Nt, uint64_t Address) { + const auto Module = reinterpret_cast(Address); + ULONG Size; + + const auto RelocationBlocksBegin = + reinterpret_cast(RtlImageDirectoryEntryToData(Module, true, IMAGE_DIRECTORY_ENTRY_BASERELOC, &Size)); + if (!RelocationBlocksBegin) { + return {}; + } + + fextl::unordered_map Result; + const uint64_t RelocationBlocksEnd = RelocationBlocksBegin + Size - sizeof(IMAGE_BASE_RELOCATION); + for (uint64_t CurrentRelocation = RelocationBlocksBegin; CurrentRelocation < RelocationBlocksEnd;) { + const auto* Block = reinterpret_cast(CurrentRelocation); + if (!Block->SizeOfBlock) { + break; + } + const uint64_t BlockEnd = CurrentRelocation + Block->SizeOfBlock; // Includes the size of IMAGE_BASE_RELOCATION + CurrentRelocation += sizeof(IMAGE_BASE_RELOCATION); + + for (; CurrentRelocation < BlockEnd; CurrentRelocation += 2) { + auto PackedRelocation = *reinterpret_cast(CurrentRelocation); + uint32_t RelocatedRVA = Block->VirtualAddress + (PackedRelocation & 0xfff); + uint8_t Type = PackedRelocation >> 12; + + switch (Type) { + case IMAGE_REL_BASED_ABSOLUTE: break; + case IMAGE_REL_BASED_HIGHLOW: Result[RelocatedRVA] = FEXCore::GuestRelocationType::Rel32; break; + case IMAGE_REL_BASED_DIR64: Result[RelocatedRVA] = FEXCore::GuestRelocationType::Rel64; break; + default: ERROR_AND_DIE_FMT("Unhandled relocation"); + } + } + } + + return Result; +} + ImageTracker::ImageTracker(FEXCore::Context::Context& CTX, bool IsGeneratingCache) : CTX {CTX} , ExtendedMetaData {FEX::VolatileMetadata::ParseExtendedVolatileMetadata(ExtendedVolatileMetadataConfig())} @@ -94,10 +131,15 @@ FEXCore::ExecutableFileSectionInfo ImageTracker::HandleImageMap(std::string_view auto* Nt = reinterpret_cast(RtlImageNtHeader(Module)); MappedImageInfo* ImageInfo = nullptr; { + auto Relocations = [&]() { + if (IsGeneratingCache) { + return LoadImageRelocations(Nt, Address); + } + return fextl::unordered_map {}; + }(); std::unique_lock Lk {ImagesLock}; - auto [It, Inserted] = - MappedImages.emplace(std::piecewise_construct, std::forward_as_tuple(Address), - std::forward_as_tuple(Path, Address, Nt, fextl::unordered_map {})); + auto [It, Inserted] = MappedImages.emplace(std::piecewise_construct, std::forward_as_tuple(Address), + std::forward_as_tuple(Path, Address, Nt, std::move(Relocations))); if (!Inserted) { return It->second.SectionInfo;