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  return false;
142}
143
144error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
145                                                             unsigned Permissions) {
146
147  for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) {
148      error_code ec;
149      ec = sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i],
150                                            Permissions);
151      if (ec) {
152        return ec;
153      }
154  }
155
156  return error_code::success();
157}
158
159void SectionMemoryManager::invalidateInstructionCache() {
160  for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
161    sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(),
162                                            CodeMem.AllocatedMem[i].size());
163}
164
165static int jit_noop() {
166  return 0;
167}
168
169void *SectionMemoryManager::getPointerToNamedFunction(const std::string &Name,
170                                                       bool AbortOnFailure) {
171#if defined(__linux__)
172  //===--------------------------------------------------------------------===//
173  // Function stubs that are invoked instead of certain library calls
174  //
175  // Force the following functions to be linked in to anything that uses the
176  // JIT. This is a hack designed to work around the all-too-clever Glibc
177  // strategy of making these functions work differently when inlined vs. when
178  // not inlined, and hiding their real definitions in a separate archive file
179  // that the dynamic linker can't see. For more info, search for
180  // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
181  if (Name == "stat") return (void*)(intptr_t)&stat;
182  if (Name == "fstat") return (void*)(intptr_t)&fstat;
183  if (Name == "lstat") return (void*)(intptr_t)&lstat;
184  if (Name == "stat64") return (void*)(intptr_t)&stat64;
185  if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
186  if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
187  if (Name == "atexit") return (void*)(intptr_t)&atexit;
188  if (Name == "mknod") return (void*)(intptr_t)&mknod;
189#endif // __linux__
190
191  // We should not invoke parent's ctors/dtors from generated main()!
192  // On Mingw and Cygwin, the symbol __main is resolved to
193  // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
194  // (and register wrong callee's dtors with atexit(3)).
195  // We expect ExecutionEngine::runStaticConstructorsDestructors()
196  // is called before ExecutionEngine::runFunctionAsMain() is called.
197  if (Name == "__main") return (void*)(intptr_t)&jit_noop;
198
199  const char *NameStr = Name.c_str();
200  void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
201  if (Ptr) return Ptr;
202
203  // If it wasn't found and if it starts with an underscore ('_') character,
204  // try again without the underscore.
205  if (NameStr[0] == '_') {
206    Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
207    if (Ptr) return Ptr;
208  }
209
210  if (AbortOnFailure)
211    report_fatal_error("Program used external function '" + Name +
212                      "' which could not be resolved!");
213  return 0;
214}
215
216SectionMemoryManager::~SectionMemoryManager() {
217  for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
218    sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]);
219  for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i)
220    sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]);
221  for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i)
222    sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]);
223}
224
225} // namespace llvm
226
227