// [AsmJit] // Complete x86/x64 JIT and Remote Assembler for C++. // // [License] // Zlib - See LICENSE.md file in the package. // [Guard] #ifndef _ASMJIT_BASE_VMEM_H #define _ASMJIT_BASE_VMEM_H // [Dependencies] #include "../base/utils.h" // [Api-Begin] #include "../apibegin.h" namespace asmjit { //! \addtogroup asmjit_base //! \{ // ============================================================================ // [asmjit::VMemAllocType] // ============================================================================ //! Type of virtual memory allocation, see `VMemMgr::alloc()`. ASMJIT_ENUM(VMemAllocType) { //! Normal memory allocation, has to be freed by `VMemMgr::release()`. kVMemAllocFreeable = 0, //! Allocate permanent memory, can't be freed. kVMemAllocPermanent = 1 }; // ============================================================================ // [asmjit::VMemFlags] // ============================================================================ //! Type of virtual memory allocation, see `VMemMgr::alloc()`. ASMJIT_ENUM(VMemFlags) { //! Memory is writable. kVMemFlagWritable = 0x00000001, //! Memory is executable. kVMemFlagExecutable = 0x00000002 }; // ============================================================================ // [asmjit::VMemUtil] // ============================================================================ //! Virtual memory utilities. //! //! Defines functions that provide facility to allocate and free memory that is //! executable in a platform independent manner. If both the processor and host //! operating system support data-execution-prevention then the only way how to //! run machine code is to allocate it to a memory that has marked as executable. //! VMemUtil is just unified interface to platform dependent APIs. //! //! `VirtualAlloc()` function is used on Windows operating system and `mmap()` //! on POSIX. `VirtualAlloc()` and `mmap()` documentation provide a detailed //! overview on how to use a platform specific APIs. struct VMemUtil { //! Get a size/alignment of a single virtual memory page. static ASMJIT_API size_t getPageSize() noexcept; //! Get a recommended granularity for a single `alloc` call. static ASMJIT_API size_t getPageGranularity() noexcept; //! Allocate virtual memory. //! //! Pages are readable/writeable, but they are not guaranteed to be //! executable unless 'canExecute' is true. Returns the address of //! allocated memory, or `nullptr` on failure. static ASMJIT_API void* alloc(size_t length, size_t* allocated, uint32_t flags) noexcept; //! Free memory allocated by `alloc()`. static ASMJIT_API Error release(void* addr, size_t length) noexcept; #if ASMJIT_OS_WINDOWS //! Allocate virtual memory of `hProcess` (Windows only). static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags) noexcept; //! Release virtual memory of `hProcess` (Windows only). static ASMJIT_API Error releaseProcessMemory(HANDLE hProcess, void* addr, size_t length) noexcept; #endif // ASMJIT_OS_WINDOWS }; // ============================================================================ // [asmjit::VMemMgr] // ============================================================================ //! Reference implementation of memory manager that uses `VMemUtil` to allocate //! chunks of virtual memory and bit arrays to manage it. class VMemMgr { public: // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- #if !ASMJIT_OS_WINDOWS //! Create a `VMemMgr` instance. ASMJIT_API VMemMgr() noexcept; #else //! Create a `VMemMgr` instance. //! //! NOTE: When running on Windows it's possible to specify a `hProcess` to //! be used for memory allocation. Using `hProcess` allows to allocate memory //! of a remote process. ASMJIT_API VMemMgr(HANDLE hProcess = static_cast(0)) noexcept; #endif // ASMJIT_OS_WINDOWS //! Destroy the `VMemMgr` instance and free all blocks. ASMJIT_API ~VMemMgr() noexcept; // -------------------------------------------------------------------------- // [Reset] // -------------------------------------------------------------------------- //! Free all allocated memory. ASMJIT_API void reset() noexcept; // -------------------------------------------------------------------------- // [Accessors] // -------------------------------------------------------------------------- #if ASMJIT_OS_WINDOWS //! Get the handle of the process memory manager is bound to. ASMJIT_INLINE HANDLE getProcessHandle() const noexcept { return _hProcess; } #endif // ASMJIT_OS_WINDOWS //! Get how many bytes are currently allocated. ASMJIT_INLINE size_t getAllocatedBytes() const noexcept { return _allocatedBytes; } //! Get how many bytes are currently used. ASMJIT_INLINE size_t getUsedBytes() const noexcept { return _usedBytes; } //! Get whether to keep allocated memory after the `VMemMgr` is destroyed. //! //! \sa \ref setKeepVirtualMemory. ASMJIT_INLINE bool getKeepVirtualMemory() const noexcept { return _keepVirtualMemory; } //! Set whether to keep allocated memory after memory manager is //! destroyed. //! //! This method is usable when patching code of remote process. You need to //! allocate process memory, store generated assembler into it and patch the //! method you want to redirect (into your code). This method affects only //! VMemMgr destructor. After destruction all internal //! structures are freed, only the process virtual memory remains. //! //! NOTE: Memory allocated with kVMemAllocPermanent is always kept. //! //! \sa \ref getKeepVirtualMemory. ASMJIT_INLINE void setKeepVirtualMemory(bool keepVirtualMemory) noexcept { _keepVirtualMemory = keepVirtualMemory; } // -------------------------------------------------------------------------- // [Alloc / Release] // -------------------------------------------------------------------------- //! Allocate a `size` bytes of virtual memory. //! //! Note that if you are implementing your own virtual memory manager then you //! can quitly ignore type of allocation. This is mainly for AsmJit to memory //! manager that allocated memory will be never freed. ASMJIT_API void* alloc(size_t size, uint32_t type = kVMemAllocFreeable) noexcept; //! Free previously allocated memory at a given `address`. ASMJIT_API Error release(void* p) noexcept; //! Free extra memory allocated with `p`. ASMJIT_API Error shrink(void* p, size_t used) noexcept; // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- #if ASMJIT_OS_WINDOWS //! Process passed to `VirtualAllocEx` and `VirtualFree`. HANDLE _hProcess; #endif // ASMJIT_OS_WINDOWS //! Lock to enable thread-safe functionality. Lock _lock; //! Default block size. size_t _blockSize; //! Default block density. size_t _blockDensity; // Whether to keep virtual memory after destroy. bool _keepVirtualMemory; //! How many bytes are currently allocated. size_t _allocatedBytes; //! How many bytes are currently used. size_t _usedBytes; //! \internal //! \{ struct RbNode; struct MemNode; struct PermanentNode; // Memory nodes root. MemNode* _root; // Memory nodes list. MemNode* _first; MemNode* _last; MemNode* _optimal; // Permanent memory. PermanentNode* _permanent; //! \} }; //! \} } // asmjit namespace // [Api-End] #include "../apiend.h" // [Guard] #endif // _ASMJIT_BASE_VMEM_H