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