1249259Sdim//===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==// 2249259Sdim// 3249259Sdim// The LLVM Compiler Infrastructure 4249259Sdim// 5249259Sdim// This file is distributed under the University of Illinois Open Source 6249259Sdim// License. See LICENSE.TXT for details. 7249259Sdim// 8249259Sdim//===----------------------------------------------------------------------===// 9249259Sdim// 10249259Sdim// This file implements the section-based memory manager used by the MCJIT 11249259Sdim// execution engine and RuntimeDyld 12249259Sdim// 13249259Sdim//===----------------------------------------------------------------------===// 14249259Sdim 15249259Sdim#include "llvm/Config/config.h" 16249259Sdim#include "llvm/ExecutionEngine/SectionMemoryManager.h" 17249259Sdim#include "llvm/Support/MathExtras.h" 18249259Sdim 19249259Sdimnamespace llvm { 20249259Sdim 21249259Sdimuint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, 22263509Sdim unsigned Alignment, 23263509Sdim unsigned SectionID, 24263509Sdim StringRef SectionName, 25263509Sdim bool IsReadOnly) { 26249259Sdim if (IsReadOnly) 27249259Sdim return allocateSection(RODataMem, Size, Alignment); 28249259Sdim return allocateSection(RWDataMem, Size, Alignment); 29249259Sdim} 30249259Sdim 31249259Sdimuint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, 32249259Sdim unsigned Alignment, 33263509Sdim unsigned SectionID, 34263509Sdim StringRef SectionName) { 35249259Sdim return allocateSection(CodeMem, Size, Alignment); 36249259Sdim} 37249259Sdim 38249259Sdimuint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, 39249259Sdim uintptr_t Size, 40249259Sdim unsigned Alignment) { 41249259Sdim if (!Alignment) 42249259Sdim Alignment = 16; 43249259Sdim 44249259Sdim assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); 45249259Sdim 46249259Sdim uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1); 47249259Sdim uintptr_t Addr = 0; 48249259Sdim 49249259Sdim // Look in the list of free memory regions and use a block there if one 50249259Sdim // is available. 51249259Sdim for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) { 52249259Sdim sys::MemoryBlock &MB = MemGroup.FreeMem[i]; 53249259Sdim if (MB.size() >= RequiredSize) { 54249259Sdim Addr = (uintptr_t)MB.base(); 55249259Sdim uintptr_t EndOfBlock = Addr + MB.size(); 56249259Sdim // Align the address. 57249259Sdim Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 58249259Sdim // Store cutted free memory block. 59249259Sdim MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size), 60249259Sdim EndOfBlock - Addr - Size); 61249259Sdim return (uint8_t*)Addr; 62249259Sdim } 63249259Sdim } 64249259Sdim 65249259Sdim // No pre-allocated free block was large enough. Allocate a new memory region. 66249259Sdim // Note that all sections get allocated as read-write. The permissions will 67249259Sdim // be updated later based on memory group. 68249259Sdim // 69249259Sdim // FIXME: It would be useful to define a default allocation size (or add 70249259Sdim // it as a constructor parameter) to minimize the number of allocations. 71249259Sdim // 72249259Sdim // FIXME: Initialize the Near member for each memory group to avoid 73249259Sdim // interleaving. 74249259Sdim error_code ec; 75249259Sdim sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize, 76249259Sdim &MemGroup.Near, 77249259Sdim sys::Memory::MF_READ | 78249259Sdim sys::Memory::MF_WRITE, 79249259Sdim ec); 80249259Sdim if (ec) { 81249259Sdim // FIXME: Add error propogation to the interface. 82249259Sdim return NULL; 83249259Sdim } 84249259Sdim 85249259Sdim // Save this address as the basis for our next request 86249259Sdim MemGroup.Near = MB; 87249259Sdim 88249259Sdim MemGroup.AllocatedMem.push_back(MB); 89249259Sdim Addr = (uintptr_t)MB.base(); 90249259Sdim uintptr_t EndOfBlock = Addr + MB.size(); 91249259Sdim 92249259Sdim // Align the address. 93249259Sdim Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 94249259Sdim 95249259Sdim // The allocateMappedMemory may allocate much more memory than we need. In 96249259Sdim // this case, we store the unused memory as a free memory block. 97249259Sdim unsigned FreeSize = EndOfBlock-Addr-Size; 98249259Sdim if (FreeSize > 16) 99249259Sdim MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); 100249259Sdim 101249259Sdim // Return aligned address 102249259Sdim return (uint8_t*)Addr; 103249259Sdim} 104249259Sdim 105263509Sdimbool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) 106249259Sdim{ 107249259Sdim // FIXME: Should in-progress permissions be reverted if an error occurs? 108249259Sdim error_code ec; 109249259Sdim 110263509Sdim // Don't allow free memory blocks to be used after setting protection flags. 111263509Sdim CodeMem.FreeMem.clear(); 112263509Sdim 113249259Sdim // Make code memory executable. 114249259Sdim ec = applyMemoryGroupPermissions(CodeMem, 115249259Sdim sys::Memory::MF_READ | sys::Memory::MF_EXEC); 116249259Sdim if (ec) { 117249259Sdim if (ErrMsg) { 118249259Sdim *ErrMsg = ec.message(); 119249259Sdim } 120249259Sdim return true; 121249259Sdim } 122249259Sdim 123263509Sdim // Don't allow free memory blocks to be used after setting protection flags. 124263509Sdim RODataMem.FreeMem.clear(); 125263509Sdim 126249259Sdim // Make read-only data memory read-only. 127249259Sdim ec = applyMemoryGroupPermissions(RODataMem, 128249259Sdim sys::Memory::MF_READ | sys::Memory::MF_EXEC); 129249259Sdim if (ec) { 130249259Sdim if (ErrMsg) { 131249259Sdim *ErrMsg = ec.message(); 132249259Sdim } 133249259Sdim return true; 134249259Sdim } 135249259Sdim 136249259Sdim // Read-write data memory already has the correct permissions 137249259Sdim 138252723Sdim // Some platforms with separate data cache and instruction cache require 139252723Sdim // explicit cache flush, otherwise JIT code manipulations (like resolved 140252723Sdim // relocations) will get to the data cache but not to the instruction cache. 141252723Sdim invalidateInstructionCache(); 142252723Sdim 143249259Sdim return false; 144249259Sdim} 145249259Sdim 146249259Sdimerror_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, 147249259Sdim unsigned Permissions) { 148249259Sdim 149249259Sdim for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) { 150249259Sdim error_code ec; 151249259Sdim ec = sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], 152249259Sdim Permissions); 153249259Sdim if (ec) { 154249259Sdim return ec; 155249259Sdim } 156249259Sdim } 157249259Sdim 158249259Sdim return error_code::success(); 159249259Sdim} 160249259Sdim 161249259Sdimvoid SectionMemoryManager::invalidateInstructionCache() { 162249259Sdim for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) 163249259Sdim sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(), 164249259Sdim CodeMem.AllocatedMem[i].size()); 165249259Sdim} 166249259Sdim 167249259SdimSectionMemoryManager::~SectionMemoryManager() { 168249259Sdim for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) 169249259Sdim sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]); 170249259Sdim for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i) 171249259Sdim sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]); 172249259Sdim for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i) 173249259Sdim sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]); 174249259Sdim} 175249259Sdim 176249259Sdim} // namespace llvm 177249259Sdim 178