diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index ee578f4ed..7e5c22673 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -41,6 +41,7 @@ $end_info$ #include #include #include +#include #include class ECSyscallHandler; @@ -109,6 +110,30 @@ bool IsDispatcherAddress(uint64_t Address) { const auto& Config = SignalDelegator->GetConfig(); return Address >= Config.DispatcherBegin && Address < Config.DispatcherEnd; } + +// GetProcAddress on ARM64EC returns a pointer to an x64 fast forward sequence to allow for redirecting to the JIT if functions are hotpatched. +// This looks up the procedure address of the native code even if the fast forward sequence has been patched. +uintptr_t GetRedirectedProcAddress(HMODULE Module, const char* ProcName) { + const uintptr_t Proc = reinterpret_cast(GetProcAddress(Module, ProcName)); + if (!Proc) { + return 0; + } + + ULONG Size; + const auto* LoadConfig = + reinterpret_cast<_IMAGE_LOAD_CONFIG_DIRECTORY64*>(RtlImageDirectoryEntryToData(Module, true, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &Size)); + const auto* CHPEMetadata = reinterpret_cast(LoadConfig->CHPEMetadataPointer); + const uintptr_t ModuleBase = reinterpret_cast(Module); + const uintptr_t ProcRVA = Proc - ModuleBase; + const auto* RedirectionTableBegin = reinterpret_cast(ModuleBase + CHPEMetadata->RedirectionMetadata); + const auto* RedirectionTableEnd = RedirectionTableBegin + CHPEMetadata->RedirectionMetadataCount; + const auto* It = + std::lower_bound(RedirectionTableBegin, RedirectionTableEnd, ProcRVA, [](const auto& Entry, uintptr_t RVA) { return Entry.Source < RVA; }); + if (It->Source != ProcRVA) { + return 0; + } + return ModuleBase + It->Destination; +} } // namespace namespace Exception {