Files
FEX-Emu--FEX/Source/Windows/Common/CallRetStack.h
T
Ryan Houdek 154ff43d7f 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.
2026-05-29 16:17:04 -07:00

54 lines
2.6 KiB
C++

// SPDX-License-Identifier: MIT
#pragma once
#include <FEXCore/Core/Context.h>
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Debug/InternalThreadState.h>
namespace FEX::Windows::CallRetStack {
struct CallRetStackInfo {
uint64_t AllocationBase;
uint64_t AllocationEnd;
uint64_t DefaultLocation;
};
CallRetStackInfo GetInfoThread(FEXCore::Core::InternalThreadState* Thread) {
uint64_t Base = reinterpret_cast<uint64_t>(Thread->CallRetStackBase);
// Leave some room from the base for the default location to allow for underflows without constant exceptions
return {Base - FEXCore::Utils::FEX_PAGE_SIZE, Base + FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + FEXCore::Utils::FEX_PAGE_SIZE,
Base + FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE / 4};
}
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 | MEM_TOP_DOWN, PAGE_NOACCESS);
FEXCore::Allocator::VirtualName("FEXMem_CallRetStacks", CallRetStackAlloc,
FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE);
FEXCore::Allocator::VirtualTHPControl(CallRetStackAlloc, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE + 2 * FEXCore::Utils::FEX_PAGE_SIZE,
FEXCore::Allocator::THPControl::Disable);
Thread->CallRetStackBase = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(CallRetStackAlloc) + FEXCore::Utils::FEX_PAGE_SIZE);
::VirtualAlloc(Thread->CallRetStackBase, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE, MEM_COMMIT, PAGE_READWRITE);
Thread->CurrentFrame->State.callret_sp = GetInfoThread(Thread).DefaultLocation;
}
void DestroyThread(FEXCore::Core::InternalThreadState* Thread) {
auto CallRetStackInfo = GetInfoThread(Thread);
::VirtualFree(reinterpret_cast<void*>(CallRetStackInfo.AllocationBase), 0, MEM_RELEASE);
}
bool HandleAccessViolation(FEXCore::Core::InternalThreadState* Thread, uint64_t Address, uint64_t& CallRetSPReg) {
auto CallRetStackInfo = GetInfoThread(Thread);
if (Address >= CallRetStackInfo.AllocationBase && Address < CallRetStackInfo.AllocationEnd) {
LogMan::Msg::DFmt("Call-ret stack inbalance: {:X}", Address);
CallRetSPReg = CallRetStackInfo.DefaultLocation;
return true;
}
return false;
}
} // namespace FEX::Windows::CallRetStack