aboutsummaryrefslogtreecommitdiff
path: root/orc-rt/lib/executor/Unix/NativeMemoryAPIs.inc
blob: 41c6632f40dd139c76cc18c6cedfdd4c59b44ae4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//===- 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