#include "Mappable.hpp" #include "mem.hpp" #include #ifndef _WIN32 #include #include #include #include #else #include #define NTDDI_VERSION NTDDI_WIN10_NI #define WIN32_LEAN_AND_MEAN #include #endif #ifdef ANDROID #include static int memfd_create(const char *name, uint flags) { // FIXME: requires modern android return syscall(__NR_memfd_create, name, flags); } #endif std::pair rx::Mappable::CreateMemory(std::size_t size) { rx::Mappable result; #ifdef _WIN32 auto handle = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_ALL_ACCESS, PAGE_EXECUTE_READWRITE, SEC_COMMIT, size, nullptr, nullptr, 0); if (!handle) { return {rx::Mappable{}, std::errc::invalid_argument}; } result.m_handle = handle; #else auto fd = ::memfd_create("", 0); if (fd < 0) { return {{}, std::errc{errno}}; } result.m_handle = fd; if (::ftruncate(fd, size) < 0) { return {{}, std::errc{errno}}; } #endif return {std::move(result), std::errc{}}; } std::pair rx::Mappable::CreateSwap(std::size_t size) { #ifdef _WIN32 return CreateMemory(size); #else char temp_filename[] = "./.rx-swap-XXXXXXXXXXX"; int fd = ::mkstemp(temp_filename); if (fd < 0) { return {{}, std::errc{errno}}; } ::unlink(temp_filename); rx::Mappable result; result.m_handle = fd; if (::ftruncate(fd, size) < 0) { return {{}, std::errc{errno}}; } return {std::move(result), {}}; #endif } std::errc rx::Mappable::map(rx::AddressRange virtualRange, std::size_t offset, rx::EnumBitSet protection, [[maybe_unused]] std::size_t alignment) { #ifdef _WIN32 static const DWORD protTable[] = { PAGE_NOACCESS, // 0 PAGE_READONLY, // R PAGE_EXECUTE_READWRITE, // W PAGE_EXECUTE_READWRITE, // RW PAGE_EXECUTE, // X PAGE_EXECUTE_READWRITE, // XR PAGE_EXECUTE_READWRITE, // XW PAGE_EXECUTE_READWRITE, // XRW }; auto prot = protTable[(protection & (mem::Protection::R | mem::Protection::W | mem::Protection::X)) .toUnderlying()]; mem::release(virtualRange, alignment); for (std::uintptr_t address = virtualRange.beginAddress(); address < virtualRange.endAddress(); address += alignment, offset += alignment) { auto pointer = std::bit_cast(address); auto result = MapViewOfFile3((HANDLE)m_handle, nullptr, pointer, offset, alignment, MEM_REPLACE_PLACEHOLDER, prot, nullptr, 0); if (!result) { return std::errc::invalid_argument; } } #else int prot = 0; if (protection & mem::Protection::R) { prot |= PROT_READ; } if (protection & mem::Protection::W) { prot |= PROT_READ | PROT_WRITE; } if (protection & mem::Protection::X) { prot |= PROT_EXEC; } auto address = std::bit_cast(virtualRange.beginAddress()); auto result = ::mmap(address, virtualRange.size(), prot, MAP_SHARED | MAP_FIXED, m_handle, offset); if (result == MAP_FAILED) { return std::errc{errno}; } #endif return {}; } void rx::Mappable::destroy() { #ifdef _WIN32 CloseHandle((HANDLE)m_handle); #else ::close(m_handle); #endif }