Files
llvm/orc-rt/lib/executor/Unix/NativeMemoryAPIs.inc
Lang Hames 891f002026 [orc-rt] Add SimpleNativeMemoryMap. (#162584)
SimpleNativeMemoryMap is a memory allocation backend for use with ORC.
It can...

1. Reserve slabs of address space.
2. Finalize regions of memory within a reserved slab: copying content
into requested addresses, applying memory protections, running
finalization actions, and storing deallocation actions to be run by
deallocate.
3. Deallocate finalized memory regions: running deallocate actions and,
if possible, making memory in these regions available for use by future
finalization operations. (Some systems prohibit reuse of executable
memory. On these systems deallocated memory is no longer usable within
the process).
4. Release reserved slabs. This runs deallocate for any
not-yet-deallocated finalized regions, and then (if possible) returns
the address space to system. (On systems that prohibit reuse of
executable memory parts of the released address space may be permanently
unusable by the process).

SimpleNativeMemoryMap is intended primarily for use by
llvm::orc::JITLinkMemoryManager implementations to allocate JIT'd code
and data.
2025-10-09 13:10:34 +11:00

104 lines
2.9 KiB
C++

//===- NativeMemoryAPIs.inc -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Generic wrappers for unix-style memory APIs (mmap, mprotect, etc.).
//
//===----------------------------------------------------------------------===//
#include "orc-rt/Error.h"
#include "orc-rt/MemoryFlags.h"
#include <fcntl.h>
#include <string.h>
#include <sys/errno.h>
#include <sys/mman.h>
namespace {
int toNativeProtFlags(orc_rt::MemProt MP) {
int Prot = PROT_NONE;
if ((MP & orc_rt::MemProt::Read) != orc_rt::MemProt::None)
Prot |= PROT_READ;
if ((MP & orc_rt::MemProt::Write) != orc_rt::MemProt::None)
Prot |= PROT_WRITE;
if ((MP & orc_rt::MemProt::Exec) != orc_rt::MemProt::None)
Prot |= PROT_EXEC;
return Prot;
}
#if defined(__APPLE__)
extern "C" void sys_icache_invalidate(const void *Addr, size_t Size);
#else
extern "C" void __clear_cache(void *Start, void *End);
#endif
static void invalidateInstructionCache(void *Addr, size_t Size) {
#if defined(__APPLE__)
sys_icache_invalidate(Addr, Size);
#else
__clear_cache(Addr, reinterpret_cast<char *>(Addr) + Size);
#endif
}
orc_rt::Expected<void *> hostOSMemoryReserve(size_t Size) {
if (Size == 0)
return nullptr;
int FD = 0;
int MapFlags = MAP_PRIVATE;
#if defined(MAP_ANON)
// If MAP_ANON is available then use it.
FD = -1;
MapFlags |= MAP_ANON;
#else // !defined(MAP_ANON)
// Fall back to /dev/zero for strict POSIX.
fd = open("/dev/zero", O_RDWR);
if (fd == -1) {
auto ErrNum = errno;
return make_error<orc_rt::StringError>(
std::string("Could not open /dev/zero for memory reserve: ") +
strerror(ErrNum));
}
#endif
void *Addr = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MapFlags, FD, 0);
if (Addr == MAP_FAILED) {
auto ErrNum = errno;
return orc_rt::make_error<orc_rt::StringError>(
std::string("mmap for memory reserve failed: ") + strerror(ErrNum));
}
return Addr;
}
orc_rt::Error hostOSMemoryRelease(void *Base, size_t Size) {
if (munmap(Base, Size) != 0) {
auto ErrNum = errno;
return orc_rt::make_error<orc_rt::StringError>(
std::string("munmap for memory release failed: ") + strerror(ErrNum));
}
return orc_rt::Error::success();
}
orc_rt::Error hostOSMemoryProtect(void *Base, size_t Size, orc_rt::MemProt MP) {
if (mprotect(Base, Size, toNativeProtFlags(MP)) != 0) {
auto ErrNum = errno;
return orc_rt::make_error<orc_rt::StringError>(
std::string("mprotect for memory finalize failed: ") +
strerror(ErrNum));
}
if ((MP & orc_rt::MemProt::Exec) != orc_rt::MemProt::None)
invalidateInstructionCache(Base, Size);
return orc_rt::Error::success();
}
} // anonymous namespace