From 154ff43d7f27e77de36c0eb160370d31098dbcde Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 29 May 2026 16:17:04 -0700 Subject: [PATCH] arm64ec: Fixes some FEX allocations that were missing TOP_DOWN We were accidentally allocating some things without this flag and it was causing us to dump memory in to the lower 32-bits on arm64ec. This was causing the game [Below](https://store.steampowered.com/app/250680/BELOW/) to run out of memory to allocate for its LUA JIT and causes it to crash. --- Source/Windows/ARM64EC/Module.cpp | 5 +++-- Source/Windows/Common/CallRetStack.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 241da1038..c628cfc27 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -619,7 +619,7 @@ NTSTATUS ProcessInit() { CPUFeatures.emplace(*CTX); - X64ReturnInstr = ::VirtualAlloc(nullptr, FEXCore::Utils::FEX_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + X64ReturnInstr = ::VirtualAlloc(nullptr, FEXCore::Utils::FEX_PAGE_SIZE, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); InvalidationTracker->HandleMemoryProtectionNotification(reinterpret_cast(X64ReturnInstr), FEXCore::Utils::FEX_PAGE_SIZE, PAGE_EXECUTE_READ); *reinterpret_cast(X64ReturnInstr) = 0xc3; @@ -919,7 +919,8 @@ NTSTATUS ThreadInit() { const auto CPUArea = GetCPUArea(); static constexpr size_t EmulatorStackSize = 0x40000; - const uint64_t EmulatorStack = reinterpret_cast(::VirtualAlloc(nullptr, EmulatorStackSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + const uint64_t EmulatorStack = + reinterpret_cast(::VirtualAlloc(nullptr, EmulatorStackSize, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE)); CPUArea.EmulatorStackLimit() = EmulatorStack; CPUArea.EmulatorStackBase() = EmulatorStack + EmulatorStackSize; diff --git a/Source/Windows/Common/CallRetStack.h b/Source/Windows/Common/CallRetStack.h index d2ddee3e0..215591b39 100644 --- a/Source/Windows/Common/CallRetStack.h +++ b/Source/Windows/Common/CallRetStack.h @@ -22,8 +22,8 @@ CallRetStackInfo GetInfoThread(FEXCore::Core::InternalThreadState* Thread) { void InitializeThread(FEXCore::Core::InternalThreadState* Thread) { // Allocate the call-ret stack with guard pages on both sides - const void* CallRetStackAlloc = ::VirtualAlloc( - nullptr, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS); + const void* CallRetStackAlloc = ::VirtualAlloc(nullptr, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE, + MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS); FEXCore::Allocator::VirtualName("FEXMem_CallRetStacks", CallRetStackAlloc, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE);