LLVM  14.0.0git
Memory.inc
Go to the documentation of this file.
1 //===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines some functions for various memory management utilities.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "Unix.h"
14 #include "llvm/Config/config.h"
15 #include "llvm/Support/Alignment.h"
16 #include "llvm/Support/DataTypes.h"
18 #include "llvm/Support/Process.h"
19 
20 #ifdef HAVE_SYS_MMAN_H
21 #include <sys/mman.h>
22 #endif
23 
24 #ifdef __APPLE__
25 #include <mach/mach.h>
26 #endif
27 
28 #ifdef __Fuchsia__
29 #include <zircon/syscalls.h>
30 #endif
31 
32 #if defined(__APPLE__)
33 extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
34 #else
35 extern "C" void __clear_cache(void *, void*);
36 #endif
37 
38 static int getPosixProtectionFlags(unsigned Flags) {
39  switch (Flags & llvm::sys::Memory::MF_RWE_MASK) {
41  return PROT_READ;
43  return PROT_WRITE;
45  return PROT_READ | PROT_WRITE;
47  return PROT_READ | PROT_EXEC;
50  return PROT_READ | PROT_WRITE | PROT_EXEC;
52 #if (defined(__FreeBSD__) || defined(__POWERPC__) || defined (__ppc__) || \
53  defined(_POWER) || defined(_ARCH_PPC))
54  // On PowerPC, having an executable page that has no read permission
55  // can have unintended consequences. The function InvalidateInstruction-
56  // Cache uses instructions dcbf and icbi, both of which are treated by
57  // the processor as loads. If the page has no read permissions,
58  // executing these instructions will result in a segmentation fault.
59  return PROT_READ | PROT_EXEC;
60 #else
61  return PROT_EXEC;
62 #endif
63  default:
64  llvm_unreachable("Illegal memory protection flag specified!");
65  }
66  // Provide a default return value as required by some compilers.
67  return PROT_NONE;
68 }
69 
70 namespace llvm {
71 namespace sys {
72 
73 MemoryBlock
74 Memory::allocateMappedMemory(size_t NumBytes,
75  const MemoryBlock *const NearBlock,
76  unsigned PFlags,
77  std::error_code &EC) {
78  EC = std::error_code();
79  if (NumBytes == 0)
80  return MemoryBlock();
81 
82  // On platforms that have it, we can use MAP_ANON to get a memory-mapped
83  // page without file backing, but we need a fallback of opening /dev/zero
84  // for strictly POSIX platforms instead.
85  int fd;
86 #if defined(MAP_ANON)
87  fd = -1;
88 #else
89  fd = open("/dev/zero", O_RDWR);
90  if (fd == -1) {
91  EC = std::error_code(errno, std::generic_category());
92  return MemoryBlock();
93  }
94 #endif
95 
96  int MMFlags = MAP_PRIVATE;
97 #if defined(MAP_ANON)
98  MMFlags |= MAP_ANON;
99 #endif
100  int Protect = getPosixProtectionFlags(PFlags);
101 
102 #if defined(__NetBSD__) && defined(PROT_MPROTECT)
103  Protect |= PROT_MPROTECT(PROT_READ | PROT_WRITE | PROT_EXEC);
104 #endif
105 
106  // Use any near hint and the page size to set a page-aligned starting address
107  uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
108  NearBlock->allocatedSize() : 0;
109  static const size_t PageSize = Process::getPageSizeEstimate();
110  const size_t NumPages = (NumBytes+PageSize-1)/PageSize;
111 
112  if (Start && Start % PageSize)
113  Start += PageSize - Start % PageSize;
114 
115  // FIXME: Handle huge page requests (MF_HUGE_HINT).
116  void *Addr = ::mmap(reinterpret_cast<void *>(Start), PageSize*NumPages, Protect,
117  MMFlags, fd, 0);
118  if (Addr == MAP_FAILED) {
119  if (NearBlock) { //Try again without a near hint
120 #if !defined(MAP_ANON)
121  close(fd);
122 #endif
123  return allocateMappedMemory(NumBytes, nullptr, PFlags, EC);
124  }
125 
126  EC = std::error_code(errno, std::generic_category());
127 #if !defined(MAP_ANON)
128  close(fd);
129 #endif
130  return MemoryBlock();
131  }
132 
133 #if !defined(MAP_ANON)
134  close(fd);
135 #endif
136 
137  MemoryBlock Result;
138  Result.Address = Addr;
139  Result.AllocatedSize = PageSize*NumPages;
140  Result.Flags = PFlags;
141 
142  // Rely on protectMappedMemory to invalidate instruction cache.
143  if (PFlags & MF_EXEC) {
144  EC = Memory::protectMappedMemory (Result, PFlags);
145  if (EC != std::error_code())
146  return MemoryBlock();
147  }
148 
149  return Result;
150 }
151 
152 std::error_code
153 Memory::releaseMappedMemory(MemoryBlock &M) {
154  if (M.Address == nullptr || M.AllocatedSize == 0)
155  return std::error_code();
156 
157  if (0 != ::munmap(M.Address, M.AllocatedSize))
158  return std::error_code(errno, std::generic_category());
159 
160  M.Address = nullptr;
161  M.AllocatedSize = 0;
162 
163  return std::error_code();
164 }
165 
166 std::error_code
167 Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) {
169  if (M.Address == nullptr || M.AllocatedSize == 0)
170  return std::error_code();
171 
172  if (!Flags)
173  return std::error_code(EINVAL, std::generic_category());
174 
175  int Protect = getPosixProtectionFlags(Flags);
176  uintptr_t Start = alignAddr((const uint8_t *)M.Address - PageSize.value() + 1, PageSize);
177  uintptr_t End = alignAddr((const uint8_t *)M.Address + M.AllocatedSize, PageSize);
178 
179  bool InvalidateCache = (Flags & MF_EXEC);
180 
181 #if defined(__arm__) || defined(__aarch64__)
182  // Certain ARM implementations treat icache clear instruction as a memory read,
183  // and CPU segfaults on trying to clear cache on !PROT_READ page. Therefore we need
184  // to temporarily add PROT_READ for the sake of flushing the instruction caches.
185  if (InvalidateCache && !(Protect & PROT_READ)) {
186  int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ);
187  if (Result != 0)
188  return std::error_code(errno, std::generic_category());
189 
190  Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize);
191  InvalidateCache = false;
192  }
193 #endif
194 
195  int Result = ::mprotect((void *)Start, End - Start, Protect);
196 
197  if (Result != 0)
198  return std::error_code(errno, std::generic_category());
199 
200  if (InvalidateCache)
201  Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize);
202 
203  return std::error_code();
204 }
205 
206 /// InvalidateInstructionCache - Before the JIT can run a block of code
207 /// that has been emitted it must invalidate the instruction cache on some
208 /// platforms.
210  size_t Len) {
211 
212 // icache invalidation for PPC and ARM.
213 #if defined(__APPLE__)
214 
215 # if (defined(__POWERPC__) || defined (__ppc__) || \
216  defined(_POWER) || defined(_ARCH_PPC) || defined(__arm__) || \
217  defined(__arm64__))
218  sys_icache_invalidate(const_cast<void *>(Addr), Len);
219 # endif
220 
221 #elif defined(__Fuchsia__)
222 
223  zx_status_t Status = zx_cache_flush(Addr, Len, ZX_CACHE_FLUSH_INSN);
224  assert(Status == ZX_OK && "cannot invalidate instruction cache");
225 
226 #else
227 
228 # if (defined(__POWERPC__) || defined (__ppc__) || \
229  defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__)
230  const size_t LineSize = 32;
231 
232  const intptr_t Mask = ~(LineSize - 1);
233  const intptr_t StartLine = ((intptr_t) Addr) & Mask;
234  const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask;
235 
236  for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
237  asm volatile("dcbf 0, %0" : : "r"(Line));
238  asm volatile("sync");
239 
240  for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
241  asm volatile("icbi 0, %0" : : "r"(Line));
242  asm volatile("isync");
243 # elif (defined(__arm__) || defined(__aarch64__) || defined(__mips__)) && \
244  defined(__GNUC__)
245  // FIXME: Can we safely always call this for __GNUC__ everywhere?
246  const char *Start = static_cast<const char *>(Addr);
247  const char *End = Start + Len;
248  __clear_cache(const_cast<char *>(Start), const_cast<char *>(End));
249 # endif
250 
251 #endif // end apple
252 
254 }
255 
256 } // namespace sys
257 } // namespace llvm
llvm::sys::Memory::MF_READ
@ MF_READ
Definition: Memory.h:55
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::sys::Memory::MF_WRITE
@ MF_WRITE
Definition: Memory.h:56
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
intptr_t
llvm::sys::Memory::InvalidateInstructionCache
static void InvalidateInstructionCache(const void *Addr, size_t Len)
InvalidateInstructionCache - Before the JIT can run a block of code that has been emitted it must inv...
ErrorHandling.h
llvm::sys::Memory::allocateMappedMemory
static MemoryBlock allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock, unsigned Flags, std::error_code &EC)
This method allocates a block of memory that is suitable for loading dynamically generated code (e....
llvm::sys::Memory::releaseMappedMemory
static std::error_code releaseMappedMemory(MemoryBlock &Block)
This method releases a block of memory that was allocated with the allocateMappedMemory method.
llvm::alignAddr
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
Definition: Alignment.h:186
Unix.h
llvm::BitmaskEnumDetail::Mask
std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
Definition: BitmaskEnum.h:80
Process.h
PageSize
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
llvm::sys::Memory::MF_RWE_MASK
@ MF_RWE_MASK
Definition: Memory.h:58
llvm::ms_demangle::QualifierMangleMode::Result
@ Result
Align
uint64_t Align
Definition: ELFObjHandler.cpp:83
llvm::sys::Memory::MF_EXEC
@ MF_EXEC
Definition: Memory.h:57
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:80
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::codeview::CompileSym2Flags::EC
@ EC
Status
Definition: SIModeRegister.cpp:28
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:134
llvm::sys::ValgrindDiscardTranslations
void ValgrindDiscardTranslations(const void *Addr, size_t Len)
Definition: Valgrind.cpp:36
Alignment.h
llvm::sys::Memory::protectMappedMemory
static std::error_code protectMappedMemory(const MemoryBlock &Block, unsigned Flags)
This method sets the protection flags for a block of memory to the state specified by /p Flags.
DataTypes.h
llvm::sys::Process::getPageSizeEstimate
static unsigned getPageSizeEstimate()
Get the process's estimated page size.
Definition: Process.h:62