asmjit::VirtMem Namespace Reference

Virtual memory management.

Classes

Enumerations

Functions

Enumeration Type Documentation

class VirtMem::CachePolicy : uint32_tenumstrong◆ 

Describes whether instruction cache should be flushed after a write operation.

ConstantDescription
kDefault 

Default policy.

In some places this would mean kFlushAfterWrite and in some places it would mean kNeverFlush. For example if it's known that an address has never been used before to execute code.

kFlushAfterWrite 

Flush instruction cache after a write operation.

kNeverFlush 

Avoid flushing instruction cache after a write operation.

class VirtMem::MemoryFlags : uint32_tenumstrong◆ 

Virtual memory access and mmap-specific flags.

ConstantDescription
kNone 

No flags.

kAccessRead 

Memory is readable.

kAccessWrite 

Memory is writable.

kAccessExecute 

Memory is executable.

kAccessReadWrite 

A combination of kAccessRead and kAccessWrite.

kAccessRW 

A combination of kAccessRead, kAccessWrite.

kAccessRX 

A combination of kAccessRead and kAccessExecute.

kAccessRWX 

A combination of kAccessRead, kAccessWrite, and kAccessExecute.

kMMapEnableMapJit 

Use a MAP_JIT flag available on Apple platforms (introduced by Mojave), which allows JIT code to be executed in a MAC bundle.

This flag may be turned on by the allocator if there is no other way of allocating executable memory.

Note
This flag can only be used with VirtMem::alloc(), MAP_JIT only works on OSX and not on iOS. When a process uses fork() the child process has no access to the pages mapped with MAP_JIT.
kMMapMaxAccessRead 

Pass PROT_MAX(PROT_READ) or PROT_MPROTECT(PROT_READ) to mmap() on platforms that support it.

This flag allows to set a "maximum access" that the memory page can get during its lifetime. Use VirtMem::protect() to change the access flags.

Note
This flag can only be used with VirtMem::alloc() and VirtMem::allocDualMapping(). However VirtMem::allocDualMapping() may automatically use this if kAccessRead is used.
kMMapMaxAccessWrite 

Pass PROT_MAX(PROT_WRITE) or PROT_MPROTECT(PROT_WRITE) to mmap() on platforms that support it.

This flag allows to set a "maximum access" that the memory page can get during its lifetime. Use VirtMem::protect() to change the access flags.

Note
This flag can only be used with VirtMem::alloc() and VirtMem::allocDualMapping(). However VirtMem::allocDualMapping() may automatically use this if kAccessWrite is used.
kMMapMaxAccessExecute 

Pass PROT_MAX(PROT_EXEC) or PROT_MPROTECT(PROT_EXEC) to mmap() on platforms that support it.

This flag allows to set a "maximum access" that the memory page can get during its lifetime. Use VirtMem::protect() to change the access flags.

Note
This flag can only be used with VirtMem::alloc() and VirtMem::allocDualMapping(). However VirtMem::allocDualMapping() may automatically use this if kAccessExecute is used.
kMMapMaxAccessReadWrite 

A combination of kMMapMaxAccessRead and kMMapMaxAccessWrite.

kMMapMaxAccessRW 

A combination of kMMapMaxAccessRead and kMMapMaxAccessWrite.

kMMapMaxAccessRX 

A combination of kMMapMaxAccessRead and kMMapMaxAccessExecute.

kMMapMaxAccessRWX 

A combination of kMMapMaxAccessRead, kMMapMaxAccessWrite, kMMapMaxAccessExecute.

kMapShared 

Use MAP_SHARED when calling mmap().

Note
In some cases MAP_SHARED may be set automatically. For example, some dual mapping implementations must use MAP_SHARED instead of MAP_PRIVATE to ensure that the OS would not apply copy on write on RW page, which would cause RX page not having the updated content.
kMMapLargePages 

Request large memory mapped pages.

Remarks
If this option is used and large page(s) cannot be mapped, the allocation will fail. Fallback to regular pages must be done by the user in this case. Higher level API such as JitAllocator provides an additional mechanism to allocate regular page(s) when large page(s) allocation fails.
kMappingPreferTmp 

Not an access flag, only used by allocDualMapping() to override the default allocation strategy to always use a 'tmp' directory instead of "/dev/shm" (on POSIX platforms).

Please note that this flag will be ignored if the operating system allows to allocate an executable memory by a different API than open() or shm_open(). For example on Linux memfd_create() is preferred and on BSDs shm_open(SHM_ANON, ...) is used if SHM_ANON is defined.

Note
This flag can only be used with VirtMem::alloc().

class VirtMem::HardenedRuntimeFlags : uint32_tenumstrong◆ 

Hardened runtime flags.

ConstantDescription
kNone 

No flags.

kEnabled 

Hardened runtime is enabled - it's not possible to have "Write & Execute" memory protection.

The runtime enforces W^X (either write or execute).

Note
If the runtime is hardened it means that an operating system specific protection is used. For example on Apple OSX it's possible to allocate memory with MAP_JIT flag and then use pthread_jit_write_protect_np() to temporarily swap access permissions for the current thread. Dual mapping is also a possibility on X86/X64 architecture.
kMapJit 

Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific, only available on OSX).

class VirtMem::ProtectJitAccess : uint32_tenumstrong◆ 

Values that can be used with protectJitMemory() function.

ConstantDescription
kReadWrite 

Protect JIT memory with Read+Write permissions.

kReadExecute 

Protect JIT memory with Read+Execute permissions.

Function Documentation

void VirtMem::flushInstructionCache(void* p, size_t size)noexcept◆ 

Flushes instruction cache in the given region.

Only useful on non-x86 architectures, however, it's a good practice to call it on any platform to make your code more portable.

Info VirtMem::info()noexcept◆ 

Returns virtual memory information, see VirtMem::Info for more details.

size_t VirtMem::largePageSize()noexcept◆ 

Returns the size of the smallest large page supported.

AsmJit only uses the smallest large page at the moment as these are usually perfectly sized for executable memory allocation (standard size is 2MB, but different sizes are possible).

Returns either the detected large page size or 0, if large page support is either not supported by AsmJit or not accessible to the process.

Error VirtMem::alloc(void** p, size_t size, MemoryFlags flags)noexcept◆ 

Allocates virtual memory by either using mmap() (POSIX) or VirtualAlloc() (Windows).

Note
size should be aligned to page size, use VirtMem::info() to obtain it. Invalid size will not be corrected by the implementation and the allocation would not succeed in such case.

Error VirtMem::release(void* p, size_t size)noexcept◆ 

Releases virtual memory previously allocated by VirtMem::alloc().

Note
The size must be the same as used by VirtMem::alloc(). If the size is not the same value the call will fail on any POSIX system, but pass on Windows, because it's implemented differently.

Error VirtMem::protect(void* p, size_t size, MemoryFlags flags)noexcept◆ 

A cross-platform wrapper around mprotect() (POSIX) and VirtualProtect() (Windows).

Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, MemoryFlags flags)noexcept◆ 

Allocates virtual memory and creates two views of it where the first view has no write access.

This is an addition to the API that should be used in cases in which the operating system either enforces W^X security policy or the application wants to use this policy by default to improve security and prevent an accidental (or purposed) self-modifying code.

The memory returned in the dm are two independent mappings of the same shared memory region. You must use VirtMem::releaseDualMapping() to release it when it's no longer needed. Never use VirtMem::release() to release the memory returned by allocDualMapping() as that would fail on Windows.

Remarks
Both pointers in dm would be set to nullptr if the function fails.

Error VirtMem::releaseDualMapping(DualMapping* dm, size_t size)noexcept◆ 

Releases virtual memory mapping previously allocated by VirtMem::allocDualMapping().

Remarks
Both pointers in dm would be set to nullptr if the function succeeds.

HardenedRuntimeInfo VirtMem::hardenedRuntimeInfo()noexcept◆ 

Returns runtime features provided by the OS.

void VirtMem::protectJitMemory(ProtectJitAccess access)noexcept◆ 

Protects access of memory mapped with MAP_JIT flag for the current thread.

Note
This feature is only available on Apple hardware (AArch64) at the moment and uses a non-portable pthread_jit_write_protect_np() call when available.

This function must be called before and after a memory mapped with MAP_JIT flag is modified. Example:

void* codePtr = ...;
size_t codeSize = ...;
memcpy(codePtr, source, codeSize);
VirtMem::flushInstructionCache(codePtr, codeSize);

See ProtectJitReadWriteScope, which makes it simpler than the code above.