SectionMemoryManager.cpp revision 259065
1//===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the section-based memory manager used by the MCJIT
11// execution engine and RuntimeDyld
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Config/config.h"
16#include "llvm/ExecutionEngine/SectionMemoryManager.h"
17#include "llvm/Support/DynamicLibrary.h"
18#include "llvm/Support/MathExtras.h"
19
20#ifdef __linux__
21  // These includes used by SectionMemoryManager::getPointerToNamedFunction()
22  // for Glibc trickery. See comments in this function for more information.
23  #ifdef HAVE_SYS_STAT_H
24    #include <sys/stat.h>
25  #endif
26  #include <fcntl.h>
27  #include <unistd.h>
28#endif
29
30namespace llvm {
31
32uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
33                                                    unsigned Alignment,
34                                                    unsigned SectionID,
35                                                    bool IsReadOnly) {
36  if (IsReadOnly)
37    return allocateSection(RODataMem, Size, Alignment);
38  return allocateSection(RWDataMem, Size, Alignment);
39}
40
41uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
42                                                   unsigned Alignment,
43                                                   unsigned SectionID) {
44  return allocateSection(CodeMem, Size, Alignment);
45}
46
47uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
48                                               uintptr_t Size,
49                                               unsigned Alignment) {
50  if (!Alignment)
51    Alignment = 16;
52
53  assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
54
55  uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1);
56  uintptr_t Addr = 0;
57
58  // Look in the list of free memory regions and use a block there if one
59  // is available.
60  for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) {
61    sys::MemoryBlock &MB = MemGroup.FreeMem[i];
62    if (MB.size() >= RequiredSize) {
63      Addr = (uintptr_t)MB.base();
64      uintptr_t EndOfBlock = Addr + MB.size();
65      // Align the address.
66      Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
67      // Store cutted free memory block.
68      MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size),
69                                             EndOfBlock - Addr - Size);
70      return (uint8_t*)Addr;
71    }
72  }
73
74  // No pre-allocated free block was large enough. Allocate a new memory region.
75  // Note that all sections get allocated as read-write.  The permissions will
76  // be updated later based on memory group.
77  //
78  // FIXME: It would be useful to define a default allocation size (or add
79  // it as a constructor parameter) to minimize the number of allocations.
80  //
81  // FIXME: Initialize the Near member for each memory group to avoid
82  // interleaving.
83  error_code ec;
84  sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
85                                                          &MemGroup.Near,
86                                                          sys::Memory::MF_READ |
87                                                            sys::Memory::MF_WRITE,
88                                                          ec);
89  if (ec) {
90    // FIXME: Add error propogation to the interface.
91    return NULL;
92  }
93
94  // Save this address as the basis for our next request
95  MemGroup.Near = MB;
96
97  MemGroup.AllocatedMem.push_back(MB);
98  Addr = (uintptr_t)MB.base();
99  uintptr_t EndOfBlock = Addr + MB.size();
100
101  // Align the address.
102  Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
103
104  // The allocateMappedMemory may allocate much more memory than we need. In
105  // this case, we store the unused memory as a free memory block.
106  unsigned FreeSize = EndOfBlock-Addr-Size;
107  if (FreeSize > 16)
108    MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize));
109
110  // Return aligned address
111  return (uint8_t*)Addr;
112}
113
114bool SectionMemoryManager::applyPermissions(std::string *ErrMsg)
115{
116  // FIXME: Should in-progress permissions be reverted if an error occurs?
117  error_code ec;
118
119  // Make code memory executable.
120  ec = applyMemoryGroupPermissions(CodeMem,
121                                   sys::Memory::MF_READ | sys::Memory::MF_EXEC);
122  if (ec) {
123    if (ErrMsg) {
124      *ErrMsg = ec.message();
125    }
126    return true;
127  }
128
129  // Make read-only data memory read-only.
130  ec = applyMemoryGroupPermissions(RODataMem,
131                                   sys::Memory::MF_READ | sys::Memory::MF_EXEC);
132  if (ec) {
133    if (ErrMsg) {
134      *ErrMsg = ec.message();
135    }
136    return true;
137  }
138
139  // Read-write data memory already has the correct permissions
140
141  // Some platforms with separate data cache and instruction cache require
142  // explicit cache flush, otherwise JIT code manipulations (like resolved
143  // relocations) will get to the data cache but not to the instruction cache.
144  invalidateInstructionCache();
145
146  return false;
147}
148
149// Determine whether we can register EH tables.
150#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
151     !defined(__USING_SJLJ_EXCEPTIONS__))
152#define HAVE_EHTABLE_SUPPORT 1
153#else
154#define HAVE_EHTABLE_SUPPORT 0
155#endif
156
157#if HAVE_EHTABLE_SUPPORT
158extern "C" void __register_frame(void*);
159
160static const char *processFDE(const char *Entry) {
161  const char *P = Entry;
162  uint32_t Length = *((uint32_t*)P);
163  P += 4;
164  uint32_t Offset = *((uint32_t*)P);
165  if (Offset != 0)
166    __register_frame((void*)Entry);
167  return P + Length;
168}
169#endif
170
171void SectionMemoryManager::registerEHFrames(StringRef SectionData) {
172#if HAVE_EHTABLE_SUPPORT
173  const char *P = SectionData.data();
174  const char *End = SectionData.data() + SectionData.size();
175  do  {
176    P = processFDE(P);
177  } while(P != End);
178#endif
179}
180
181error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
182                                                             unsigned Permissions) {
183
184  for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) {
185      error_code ec;
186      ec = sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i],
187                                            Permissions);
188      if (ec) {
189        return ec;
190      }
191  }
192
193  return error_code::success();
194}
195
196void SectionMemoryManager::invalidateInstructionCache() {
197  for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
198    sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(),
199                                            CodeMem.AllocatedMem[i].size());
200}
201
202static int jit_noop() {
203  return 0;
204}
205
206void *SectionMemoryManager::getPointerToNamedFunction(const std::string &Name,
207                                                       bool AbortOnFailure) {
208#if defined(__linux__)
209  //===--------------------------------------------------------------------===//
210  // Function stubs that are invoked instead of certain library calls
211  //
212  // Force the following functions to be linked in to anything that uses the
213  // JIT. This is a hack designed to work around the all-too-clever Glibc
214  // strategy of making these functions work differently when inlined vs. when
215  // not inlined, and hiding their real definitions in a separate archive file
216  // that the dynamic linker can't see. For more info, search for
217  // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
218  if (Name == "stat") return (void*)(intptr_t)&stat;
219  if (Name == "fstat") return (void*)(intptr_t)&fstat;
220  if (Name == "lstat") return (void*)(intptr_t)&lstat;
221  if (Name == "stat64") return (void*)(intptr_t)&stat64;
222  if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
223  if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
224  if (Name == "atexit") return (void*)(intptr_t)&atexit;
225  if (Name == "mknod") return (void*)(intptr_t)&mknod;
226#endif // __linux__
227
228  // We should not invoke parent's ctors/dtors from generated main()!
229  // On Mingw and Cygwin, the symbol __main is resolved to
230  // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
231  // (and register wrong callee's dtors with atexit(3)).
232  // We expect ExecutionEngine::runStaticConstructorsDestructors()
233  // is called before ExecutionEngine::runFunctionAsMain() is called.
234  if (Name == "__main") return (void*)(intptr_t)&jit_noop;
235
236  const char *NameStr = Name.c_str();
237  void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
238  if (Ptr) return Ptr;
239
240  // If it wasn't found and if it starts with an underscore ('_') character,
241  // try again without the underscore.
242  if (NameStr[0] == '_') {
243    Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
244    if (Ptr) return Ptr;
245  }
246
247  if (AbortOnFailure)
248    report_fatal_error("Program used external function '" + Name +
249                      "' which could not be resolved!");
250  return 0;
251}
252
253SectionMemoryManager::~SectionMemoryManager() {
254  for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
255    sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]);
256  for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i)
257    sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]);
258  for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i)
259    sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]);
260}
261
262} // namespace llvm
263
264