Skip to content

Commit

Permalink
Merge branch 'main' of github.com:gdlocalisation/gdl-geode
Browse files Browse the repository at this point in the history
  • Loading branch information
JaanDev committed Jan 6, 2025
2 parents e3ae9f4 + 8849b3f commit e5c90fb
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 701 deletions.
76 changes: 76 additions & 0 deletions api/PageManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <PageManager.hpp>

using namespace geode::prelude;

void PageManager::freeAll() {
for (auto& page : m_pages) {
page.free();
}
}

PageManager::Page& PageManager::getPageForSize(size_t size) {
if (m_pages.size() > 0 && m_pages.back().canFit(size)) {
return m_pages.back();
} else {
return allocNewPage();
}
}

uint8_t* PageManager::getMemoryForSize(size_t size) {
auto& page = getPageForSize(size);
auto ret = page.getOffsetAddress();
page.reserve(size);
return ret;
}

PageManager::Page& PageManager::allocNewPage() {
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);

const uint64_t PAGE_SIZE = sysInfo.dwPageSize;
auto targetAddr = base::get() + 0x251000; // approximately the middle of the exe file
void* newPageAddr = nullptr;
uint64_t startAddr = (uint64_t(targetAddr) & ~(PAGE_SIZE - 1)); // round down to nearest page boundary
uint64_t minAddr = std::min(startAddr - 0x7FFFFF00, (uint64_t)sysInfo.lpMinimumApplicationAddress);
uint64_t maxAddr = std::max(startAddr + 0x7FFFFF00, (uint64_t)sysInfo.lpMaximumApplicationAddress);
uint64_t startPage = (startAddr - (startAddr % PAGE_SIZE));
uint64_t pageOffset = 1;

while (1) {
uint64_t byteOffset = pageOffset * PAGE_SIZE;
uint64_t highAddr = startPage + byteOffset;
uint64_t lowAddr = (startPage > byteOffset) ? startPage - byteOffset : 0;
bool needsExit = highAddr > maxAddr && lowAddr < minAddr;

if (highAddr < maxAddr) {
void* outAddr = VirtualAlloc((void*)highAddr, PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (outAddr) {
newPageAddr = outAddr;
break;
}
}

if (lowAddr > minAddr) {
void* outAddr = VirtualAlloc((void*)lowAddr, PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (outAddr != nullptr) {
newPageAddr = outAddr;
break;
}
}

pageOffset++;

if (needsExit) {
break;
}
}

if (newPageAddr == nullptr) {
log::error("page failed to alloc (what?)");
throw std::runtime_error("gdl: page failed to alloc");
}

m_pages.push_back(Page {.m_address = (uint8_t*)newPageAddr, .m_totalSize = PAGE_SIZE, .m_offset = 0, .m_id = m_pages.size()});

return m_pages.back();
}
46 changes: 46 additions & 0 deletions api/PageManager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once
#include <Geode/Geode.hpp>

#if defined(GEODE_IS_WINDOWS64)

class PageManager {
struct Page {
uint8_t* m_address;
size_t m_totalSize;
size_t m_offset; // aka used size
size_t m_id;

inline uint8_t* getOffsetAddress() { return m_address + m_offset; }
inline bool canFit(size_t len) { return m_totalSize - m_offset >= len; }
inline void reserve(size_t len) { m_offset = std::min(m_offset + len, m_totalSize); }
void free() {
if (m_address) {
VirtualFree(m_address, m_totalSize, MEM_RELEASE);
m_address = nullptr;
m_totalSize = 0;
m_offset = 0;
}
}
};

public:
static PageManager& get() {
static PageManager inst;
return inst;
}

~PageManager() { freeAll(); }

void freeAll();

// if the last page can fit those bytes, return it. otherwise, alloc a new page
Page& getPageForSize(size_t size);
uint8_t* getMemoryForSize(size_t size);

private:
Page& allocNewPage();

std::vector<Page> m_pages;
};

#endif
Loading

0 comments on commit e5c90fb

Please sign in to comment.