| //===- 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 |