| //===- 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(); | |
| } | |
| } // namespace |