LLVM  15.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 #include "llvm/Support/Valgrind.h"
20 
21 #ifdef HAVE_SYS_MMAN_H
22 #include <sys/mman.h>
23 #endif
24 
25 #ifdef __APPLE__
26 #include <mach/mach.h>
27 #endif
28 
29 #ifdef __Fuchsia__
30 #include <zircon/syscalls.h>
31 #endif
32 
33 #if defined(__APPLE__)
34 extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
35 #else
36 extern "C" void __clear_cache(void *, void*);
37 #endif
38 
39 static int getPosixProtectionFlags(unsigned Flags) {
40  switch (Flags & llvm::sys::Memory::MF_RWE_MASK) {
42  return PROT_READ;
44  return PROT_WRITE;
46  return PROT_READ | PROT_WRITE;
48  return PROT_READ | PROT_EXEC;
51  return PROT_READ | PROT_WRITE | PROT_EXEC;
53 #if (defined(__FreeBSD__) || defined(__POWERPC__) || defined (__ppc__) || \
54  defined(_POWER) || defined(_ARCH_PPC))
55  // On PowerPC, having an executable page that has no read permission
56  // can have unintended consequences. The function InvalidateInstruction-
57  // Cache uses instructions dcbf and icbi, both of which are treated by
58  // the processor as loads. If the page has no read permissions,
59  // executing these instructions will result in a segmentation fault.
60  return PROT_READ | PROT_EXEC;
61 #else
62  return PROT_EXEC;
63 #endif
64  default:
65  llvm_unreachable("Illegal memory protection flag specified!");
66  }
67  // Provide a default return value as required by some compilers.
68  return PROT_NONE;
69 }
70 
71 namespace llvm {
72 namespace sys {
73 
74 MemoryBlock
75 Memory::allocateMappedMemory(size_t NumBytes,
76  const MemoryBlock *const NearBlock,
77  unsigned PFlags,
78  std::error_code &EC) {
79  EC = std::error_code();
80  if (NumBytes == 0)
81  return MemoryBlock();
82 
83  // On platforms that have it, we can use MAP_ANON to get a memory-mapped
84  // page without file backing, but we need a fallback of opening /dev/zero
85  // for strictly POSIX platforms instead.
86  int fd;
87 #if defined(MAP_ANON)
88  fd = -1;
89 #else
90  fd = open("/dev/zero", O_RDWR);
91  if (fd == -1) {
92  EC = std::error_code(errno, std::generic_category());
93  return MemoryBlock();
94  }
95 #endif
96 
97  int MMFlags = MAP_PRIVATE;
98 #if defined(MAP_ANON)
99  MMFlags |= MAP_ANON;
100 #endif
101  int Protect = getPosixProtectionFlags(PFlags);
102 
103 #if defined(__NetBSD__) && defined(PROT_MPROTECT)
104  Protect |= PROT_MPROTECT(PROT_READ | PROT_WRITE | PROT_EXEC);
105 #endif
106 
107  // Use any near hint and the page size to set a page-aligned starting address
108  uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
109  NearBlock->allocatedSize() : 0;
110  static const size_t PageSize = Process::getPageSizeEstimate();
111  const size_t NumPages = (NumBytes+PageSize-1)/PageSize;
112 
113  if (Start && Start % PageSize)
114  Start += PageSize - Start % PageSize;
115 
116  // FIXME: Handle huge page requests (MF_HUGE_HINT).
117  void *Addr = ::mmap(reinterpret_cast<void *>(Start), PageSize*NumPages, Protect,
118  MMFlags, fd, 0);
119  if (Addr == MAP_FAILED) {
120  if (NearBlock) { //Try again without a near hint
121 #if !defined(MAP_ANON)
122  close(fd);
123 #endif
124  return allocateMappedMemory(NumBytes, nullptr, PFlags, EC);
125  }
126 
127  EC = std::error_code(errno, std::generic_category());
128 #if !defined(MAP_ANON)
129  close(fd);
130 #endif
131  return MemoryBlock();
132  }
133 
134 #if !defined(MAP_ANON)
135  close(fd);
136 #endif
137 
138  MemoryBlock Result;
139  Result.Address = Addr;
140  Result.AllocatedSize = PageSize*NumPages;
141  Result.Flags = PFlags;
142 
143  // Rely on protectMappedMemory to invalidate instruction cache.
144  if (PFlags & MF_EXEC) {
145  EC = Memory::protectMappedMemory (Result, PFlags);
146  if (EC != std::error_code())
147  return MemoryBlock();
148  }
149 
150  return Result;
151 }
152 
153 std::error_code
154 Memory::releaseMappedMemory(MemoryBlock &M) {
155  if (M.Address == nullptr || M.AllocatedSize == 0)
156  return std::error_code();
157 
158  if (0 != ::munmap(M.Address, M.AllocatedSize))
159  return std::error_code(errno, std::generic_category());
160 
161  M.Address = nullptr;
162  M.AllocatedSize = 0;
163 
164  return std::error_code();
165 }
166 
167 std::error_code
168 Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) {
170  if (M.Address == nullptr || M.AllocatedSize == 0)
171  return std::error_code();
172 
173  if (!Flags)
174  return std::error_code(EINVAL, std::generic_category());
175 
176  int Protect = getPosixProtectionFlags(Flags);
177  uintptr_t Start = alignAddr((const uint8_t *)M.Address - PageSize.value() + 1, PageSize);
178  uintptr_t End = alignAddr((const uint8_t *)M.Address + M.AllocatedSize, PageSize);
179 
180  bool InvalidateCache = (Flags & MF_EXEC);
181 
182 #if defined(__arm__) || defined(__aarch64__)
183  // Certain ARM implementations treat icache clear instruction as a memory read,
184  // and CPU segfaults on trying to clear cache on !PROT_READ page. Therefore we need
185  // to temporarily add PROT_READ for the sake of flushing the instruction caches.
186  if (InvalidateCache && !(Protect & PROT_READ)) {
187  int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ);
188  if (Result != 0)
189  return std::error_code(errno, std::generic_category());
190 
191  Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize);
192  InvalidateCache = false;
193  }
194 #endif
195 
196  int Result = ::mprotect((void *)Start, End - Start, Protect);
197 
198  if (Result != 0)
199  return std::error_code(errno, std::generic_category());
200 
201  if (InvalidateCache)
202  Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize);
203 
204  return std::error_code();
205 }
206 
207 /// InvalidateInstructionCache - Before the JIT can run a block of code
208 /// that has been emitted it must invalidate the instruction cache on some
209 /// platforms.
211  size_t Len) {
212 
213 // icache invalidation for PPC and ARM.
214 #if defined(__APPLE__)
215 
216 # if (defined(__POWERPC__) || defined (__ppc__) || \
217  defined(_POWER) || defined(_ARCH_PPC) || defined(__arm__) || \
218  defined(__arm64__))
219  sys_icache_invalidate(const_cast<void *>(Addr), Len);
220 # endif
221 
222 #elif defined(__Fuchsia__)
223 
224  zx_status_t Status = zx_cache_flush(Addr, Len, ZX_CACHE_FLUSH_INSN);
225  assert(Status == ZX_OK && "cannot invalidate instruction cache");
226 
227 #else
228 
229 # if (defined(__POWERPC__) || defined (__ppc__) || \
230  defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__)
231  const size_t LineSize = 32;
232 
233  const intptr_t Mask = ~(LineSize - 1);
234  const intptr_t StartLine = ((intptr_t) Addr) & Mask;
235  const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask;
236 
237  for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
238  asm volatile("dcbf 0, %0" : : "r"(Line));
239  asm volatile("sync");
240 
241  for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
242  asm volatile("icbi 0, %0" : : "r"(Line));
243  asm volatile("isync");
244 # elif (defined(__arm__) || defined(__aarch64__) || defined(__mips__)) && \
245  defined(__GNUC__)
246  // FIXME: Can we safely always call this for __GNUC__ everywhere?
247  const char *Start = static_cast<const char *>(Addr);
248  const char *End = Start + Len;
249  __clear_cache(const_cast<char *>(Start), const_cast<char *>(End));
250 # endif
251 
252 #endif // end apple
253 
255 }
256 
257 } // namespace sys
258 } // 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: AddressRanges.h:17
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:188
Unix.h
llvm::BitmaskEnumDetail::Mask
constexpr 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:81
llvm::sys::Memory::MF_EXEC
@ MF_EXEC
Definition: Memory.h:57
Valgrind.h
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:78
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::codeview::CompileSym2Flags::EC
@ EC
Status
Definition: SIModeRegister.cpp:29
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
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:61