1*8a6f3554SLang Hames //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==// 2*8a6f3554SLang Hames // 3*8a6f3554SLang Hames // The LLVM Compiler Infrastructure 4*8a6f3554SLang Hames // 5*8a6f3554SLang Hames // This file is distributed under the University of Illinois Open Source 6*8a6f3554SLang Hames // License. See LICENSE.TXT for details. 7*8a6f3554SLang Hames // 8*8a6f3554SLang Hames //===----------------------------------------------------------------------===// 9*8a6f3554SLang Hames // 10*8a6f3554SLang Hames // This file implements the section-based memory manager used by the MCJIT 11*8a6f3554SLang Hames // execution engine and RuntimeDyld 12*8a6f3554SLang Hames // 13*8a6f3554SLang Hames //===----------------------------------------------------------------------===// 14*8a6f3554SLang Hames 15*8a6f3554SLang Hames #include "llvm/Config/config.h" 16*8a6f3554SLang Hames #include "llvm/ExecutionEngine/SectionMemoryManager.h" 17*8a6f3554SLang Hames #include "llvm/Support/MathExtras.h" 18*8a6f3554SLang Hames 19*8a6f3554SLang Hames namespace llvm { 20*8a6f3554SLang Hames 21*8a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, 22*8a6f3554SLang Hames unsigned Alignment, 23*8a6f3554SLang Hames unsigned SectionID, 24*8a6f3554SLang Hames StringRef SectionName, 25*8a6f3554SLang Hames bool IsReadOnly) { 26*8a6f3554SLang Hames if (IsReadOnly) 27*8a6f3554SLang Hames return allocateSection(RODataMem, Size, Alignment); 28*8a6f3554SLang Hames return allocateSection(RWDataMem, Size, Alignment); 29*8a6f3554SLang Hames } 30*8a6f3554SLang Hames 31*8a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, 32*8a6f3554SLang Hames unsigned Alignment, 33*8a6f3554SLang Hames unsigned SectionID, 34*8a6f3554SLang Hames StringRef SectionName) { 35*8a6f3554SLang Hames return allocateSection(CodeMem, Size, Alignment); 36*8a6f3554SLang Hames } 37*8a6f3554SLang Hames 38*8a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, 39*8a6f3554SLang Hames uintptr_t Size, 40*8a6f3554SLang Hames unsigned Alignment) { 41*8a6f3554SLang Hames if (!Alignment) 42*8a6f3554SLang Hames Alignment = 16; 43*8a6f3554SLang Hames 44*8a6f3554SLang Hames assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); 45*8a6f3554SLang Hames 46*8a6f3554SLang Hames uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1); 47*8a6f3554SLang Hames uintptr_t Addr = 0; 48*8a6f3554SLang Hames 49*8a6f3554SLang Hames // Look in the list of free memory regions and use a block there if one 50*8a6f3554SLang Hames // is available. 51*8a6f3554SLang Hames for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) { 52*8a6f3554SLang Hames sys::MemoryBlock &MB = MemGroup.FreeMem[i]; 53*8a6f3554SLang Hames if (MB.size() >= RequiredSize) { 54*8a6f3554SLang Hames Addr = (uintptr_t)MB.base(); 55*8a6f3554SLang Hames uintptr_t EndOfBlock = Addr + MB.size(); 56*8a6f3554SLang Hames // Align the address. 57*8a6f3554SLang Hames Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 58*8a6f3554SLang Hames // Store cutted free memory block. 59*8a6f3554SLang Hames MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size), 60*8a6f3554SLang Hames EndOfBlock - Addr - Size); 61*8a6f3554SLang Hames return (uint8_t*)Addr; 62*8a6f3554SLang Hames } 63*8a6f3554SLang Hames } 64*8a6f3554SLang Hames 65*8a6f3554SLang Hames // No pre-allocated free block was large enough. Allocate a new memory region. 66*8a6f3554SLang Hames // Note that all sections get allocated as read-write. The permissions will 67*8a6f3554SLang Hames // be updated later based on memory group. 68*8a6f3554SLang Hames // 69*8a6f3554SLang Hames // FIXME: It would be useful to define a default allocation size (or add 70*8a6f3554SLang Hames // it as a constructor parameter) to minimize the number of allocations. 71*8a6f3554SLang Hames // 72*8a6f3554SLang Hames // FIXME: Initialize the Near member for each memory group to avoid 73*8a6f3554SLang Hames // interleaving. 74*8a6f3554SLang Hames std::error_code ec; 75*8a6f3554SLang Hames sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize, 76*8a6f3554SLang Hames &MemGroup.Near, 77*8a6f3554SLang Hames sys::Memory::MF_READ | 78*8a6f3554SLang Hames sys::Memory::MF_WRITE, 79*8a6f3554SLang Hames ec); 80*8a6f3554SLang Hames if (ec) { 81*8a6f3554SLang Hames // FIXME: Add error propagation to the interface. 82*8a6f3554SLang Hames return nullptr; 83*8a6f3554SLang Hames } 84*8a6f3554SLang Hames 85*8a6f3554SLang Hames // Save this address as the basis for our next request 86*8a6f3554SLang Hames MemGroup.Near = MB; 87*8a6f3554SLang Hames 88*8a6f3554SLang Hames MemGroup.AllocatedMem.push_back(MB); 89*8a6f3554SLang Hames Addr = (uintptr_t)MB.base(); 90*8a6f3554SLang Hames uintptr_t EndOfBlock = Addr + MB.size(); 91*8a6f3554SLang Hames 92*8a6f3554SLang Hames // Align the address. 93*8a6f3554SLang Hames Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 94*8a6f3554SLang Hames 95*8a6f3554SLang Hames // The allocateMappedMemory may allocate much more memory than we need. In 96*8a6f3554SLang Hames // this case, we store the unused memory as a free memory block. 97*8a6f3554SLang Hames unsigned FreeSize = EndOfBlock-Addr-Size; 98*8a6f3554SLang Hames if (FreeSize > 16) 99*8a6f3554SLang Hames MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); 100*8a6f3554SLang Hames 101*8a6f3554SLang Hames // Return aligned address 102*8a6f3554SLang Hames return (uint8_t*)Addr; 103*8a6f3554SLang Hames } 104*8a6f3554SLang Hames 105*8a6f3554SLang Hames bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) 106*8a6f3554SLang Hames { 107*8a6f3554SLang Hames // FIXME: Should in-progress permissions be reverted if an error occurs? 108*8a6f3554SLang Hames std::error_code ec; 109*8a6f3554SLang Hames 110*8a6f3554SLang Hames // Don't allow free memory blocks to be used after setting protection flags. 111*8a6f3554SLang Hames CodeMem.FreeMem.clear(); 112*8a6f3554SLang Hames 113*8a6f3554SLang Hames // Make code memory executable. 114*8a6f3554SLang Hames ec = applyMemoryGroupPermissions(CodeMem, 115*8a6f3554SLang Hames sys::Memory::MF_READ | sys::Memory::MF_EXEC); 116*8a6f3554SLang Hames if (ec) { 117*8a6f3554SLang Hames if (ErrMsg) { 118*8a6f3554SLang Hames *ErrMsg = ec.message(); 119*8a6f3554SLang Hames } 120*8a6f3554SLang Hames return true; 121*8a6f3554SLang Hames } 122*8a6f3554SLang Hames 123*8a6f3554SLang Hames // Don't allow free memory blocks to be used after setting protection flags. 124*8a6f3554SLang Hames RODataMem.FreeMem.clear(); 125*8a6f3554SLang Hames 126*8a6f3554SLang Hames // Make read-only data memory read-only. 127*8a6f3554SLang Hames ec = applyMemoryGroupPermissions(RODataMem, 128*8a6f3554SLang Hames sys::Memory::MF_READ | sys::Memory::MF_EXEC); 129*8a6f3554SLang Hames if (ec) { 130*8a6f3554SLang Hames if (ErrMsg) { 131*8a6f3554SLang Hames *ErrMsg = ec.message(); 132*8a6f3554SLang Hames } 133*8a6f3554SLang Hames return true; 134*8a6f3554SLang Hames } 135*8a6f3554SLang Hames 136*8a6f3554SLang Hames // Read-write data memory already has the correct permissions 137*8a6f3554SLang Hames 138*8a6f3554SLang Hames // Some platforms with separate data cache and instruction cache require 139*8a6f3554SLang Hames // explicit cache flush, otherwise JIT code manipulations (like resolved 140*8a6f3554SLang Hames // relocations) will get to the data cache but not to the instruction cache. 141*8a6f3554SLang Hames invalidateInstructionCache(); 142*8a6f3554SLang Hames 143*8a6f3554SLang Hames return false; 144*8a6f3554SLang Hames } 145*8a6f3554SLang Hames 146*8a6f3554SLang Hames std::error_code 147*8a6f3554SLang Hames SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, 148*8a6f3554SLang Hames unsigned Permissions) { 149*8a6f3554SLang Hames 150*8a6f3554SLang Hames for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) { 151*8a6f3554SLang Hames std::error_code ec; 152*8a6f3554SLang Hames ec = 153*8a6f3554SLang Hames sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], Permissions); 154*8a6f3554SLang Hames if (ec) { 155*8a6f3554SLang Hames return ec; 156*8a6f3554SLang Hames } 157*8a6f3554SLang Hames } 158*8a6f3554SLang Hames 159*8a6f3554SLang Hames return std::error_code(); 160*8a6f3554SLang Hames } 161*8a6f3554SLang Hames 162*8a6f3554SLang Hames void SectionMemoryManager::invalidateInstructionCache() { 163*8a6f3554SLang Hames for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) 164*8a6f3554SLang Hames sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(), 165*8a6f3554SLang Hames CodeMem.AllocatedMem[i].size()); 166*8a6f3554SLang Hames } 167*8a6f3554SLang Hames 168*8a6f3554SLang Hames SectionMemoryManager::~SectionMemoryManager() { 169*8a6f3554SLang Hames for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) 170*8a6f3554SLang Hames sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]); 171*8a6f3554SLang Hames for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i) 172*8a6f3554SLang Hames sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]); 173*8a6f3554SLang Hames for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i) 174*8a6f3554SLang Hames sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]); 175*8a6f3554SLang Hames } 176*8a6f3554SLang Hames 177*8a6f3554SLang Hames } // namespace llvm 178*8a6f3554SLang Hames 179