18a6f3554SLang Hames //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==// 28a6f3554SLang Hames // 38a6f3554SLang Hames // The LLVM Compiler Infrastructure 48a6f3554SLang Hames // 58a6f3554SLang Hames // This file is distributed under the University of Illinois Open Source 68a6f3554SLang Hames // License. See LICENSE.TXT for details. 78a6f3554SLang Hames // 88a6f3554SLang Hames //===----------------------------------------------------------------------===// 98a6f3554SLang Hames // 108a6f3554SLang Hames // This file implements the section-based memory manager used by the MCJIT 118a6f3554SLang Hames // execution engine and RuntimeDyld 128a6f3554SLang Hames // 138a6f3554SLang Hames //===----------------------------------------------------------------------===// 148a6f3554SLang Hames 158a6f3554SLang Hames #include "llvm/Config/config.h" 168a6f3554SLang Hames #include "llvm/ExecutionEngine/SectionMemoryManager.h" 178a6f3554SLang Hames #include "llvm/Support/MathExtras.h" 18*94f181a4SKeno Fischer #include "llvm/Support/Process.h" 198a6f3554SLang Hames 208a6f3554SLang Hames namespace llvm { 218a6f3554SLang Hames 228a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, 238a6f3554SLang Hames unsigned Alignment, 248a6f3554SLang Hames unsigned SectionID, 258a6f3554SLang Hames StringRef SectionName, 268a6f3554SLang Hames bool IsReadOnly) { 278a6f3554SLang Hames if (IsReadOnly) 288a6f3554SLang Hames return allocateSection(RODataMem, Size, Alignment); 298a6f3554SLang Hames return allocateSection(RWDataMem, Size, Alignment); 308a6f3554SLang Hames } 318a6f3554SLang Hames 328a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, 338a6f3554SLang Hames unsigned Alignment, 348a6f3554SLang Hames unsigned SectionID, 358a6f3554SLang Hames StringRef SectionName) { 368a6f3554SLang Hames return allocateSection(CodeMem, Size, Alignment); 378a6f3554SLang Hames } 388a6f3554SLang Hames 398a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, 408a6f3554SLang Hames uintptr_t Size, 418a6f3554SLang Hames unsigned Alignment) { 428a6f3554SLang Hames if (!Alignment) 438a6f3554SLang Hames Alignment = 16; 448a6f3554SLang Hames 458a6f3554SLang Hames assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); 468a6f3554SLang Hames 478a6f3554SLang Hames uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1); 488a6f3554SLang Hames uintptr_t Addr = 0; 498a6f3554SLang Hames 508a6f3554SLang Hames // Look in the list of free memory regions and use a block there if one 518a6f3554SLang Hames // is available. 52*94f181a4SKeno Fischer for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { 53*94f181a4SKeno Fischer if (FreeMB.Free.size() >= RequiredSize) { 54*94f181a4SKeno Fischer Addr = (uintptr_t)FreeMB.Free.base(); 55*94f181a4SKeno Fischer uintptr_t EndOfBlock = Addr + FreeMB.Free.size(); 568a6f3554SLang Hames // Align the address. 578a6f3554SLang Hames Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 58*94f181a4SKeno Fischer 59*94f181a4SKeno Fischer if (FreeMB.PendingPrefixIndex == (unsigned)-1) { 60*94f181a4SKeno Fischer // The part of the block we're giving out to the user is now pending 61*94f181a4SKeno Fischer MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); 62*94f181a4SKeno Fischer 63*94f181a4SKeno Fischer // Remember this pending block, such that future allocations can just 64*94f181a4SKeno Fischer // modify it rather than creating a new one 65*94f181a4SKeno Fischer FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1; 66*94f181a4SKeno Fischer } else { 67*94f181a4SKeno Fischer sys::MemoryBlock &PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex]; 68*94f181a4SKeno Fischer PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base()); 69*94f181a4SKeno Fischer } 70*94f181a4SKeno Fischer 71*94f181a4SKeno Fischer // Remember how much free space is now left in this block 72*94f181a4SKeno Fischer FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size); 738a6f3554SLang Hames return (uint8_t*)Addr; 748a6f3554SLang Hames } 758a6f3554SLang Hames } 768a6f3554SLang Hames 778a6f3554SLang Hames // No pre-allocated free block was large enough. Allocate a new memory region. 788a6f3554SLang Hames // Note that all sections get allocated as read-write. The permissions will 798a6f3554SLang Hames // be updated later based on memory group. 808a6f3554SLang Hames // 818a6f3554SLang Hames // FIXME: It would be useful to define a default allocation size (or add 828a6f3554SLang Hames // it as a constructor parameter) to minimize the number of allocations. 838a6f3554SLang Hames // 848a6f3554SLang Hames // FIXME: Initialize the Near member for each memory group to avoid 858a6f3554SLang Hames // interleaving. 868a6f3554SLang Hames std::error_code ec; 878a6f3554SLang Hames sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize, 888a6f3554SLang Hames &MemGroup.Near, 898a6f3554SLang Hames sys::Memory::MF_READ | 908a6f3554SLang Hames sys::Memory::MF_WRITE, 918a6f3554SLang Hames ec); 928a6f3554SLang Hames if (ec) { 938a6f3554SLang Hames // FIXME: Add error propagation to the interface. 948a6f3554SLang Hames return nullptr; 958a6f3554SLang Hames } 968a6f3554SLang Hames 978a6f3554SLang Hames // Save this address as the basis for our next request 988a6f3554SLang Hames MemGroup.Near = MB; 998a6f3554SLang Hames 100*94f181a4SKeno Fischer // Remember that we allocated this memory 101*94f181a4SKeno Fischer MemGroup.AllocatedMem.push_back(MB); 1028a6f3554SLang Hames Addr = (uintptr_t)MB.base(); 1038a6f3554SLang Hames uintptr_t EndOfBlock = Addr + MB.size(); 1048a6f3554SLang Hames 1058a6f3554SLang Hames // Align the address. 1068a6f3554SLang Hames Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 1078a6f3554SLang Hames 108*94f181a4SKeno Fischer // The part of the block we're giving out to the user is now pending 109*94f181a4SKeno Fischer MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); 110*94f181a4SKeno Fischer 1118a6f3554SLang Hames // The allocateMappedMemory may allocate much more memory than we need. In 1128a6f3554SLang Hames // this case, we store the unused memory as a free memory block. 1138a6f3554SLang Hames unsigned FreeSize = EndOfBlock-Addr-Size; 114*94f181a4SKeno Fischer if (FreeSize > 16) { 115*94f181a4SKeno Fischer FreeMemBlock FreeMB; 116*94f181a4SKeno Fischer FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize); 117*94f181a4SKeno Fischer FreeMB.PendingPrefixIndex = (unsigned)-1; 118*94f181a4SKeno Fischer MemGroup.FreeMem.push_back(FreeMB); 119*94f181a4SKeno Fischer } 1208a6f3554SLang Hames 1218a6f3554SLang Hames // Return aligned address 1228a6f3554SLang Hames return (uint8_t*)Addr; 1238a6f3554SLang Hames } 1248a6f3554SLang Hames 1258a6f3554SLang Hames bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) 1268a6f3554SLang Hames { 1278a6f3554SLang Hames // FIXME: Should in-progress permissions be reverted if an error occurs? 1288a6f3554SLang Hames std::error_code ec; 1298a6f3554SLang Hames 1308a6f3554SLang Hames // Make code memory executable. 1318a6f3554SLang Hames ec = applyMemoryGroupPermissions(CodeMem, 1328a6f3554SLang Hames sys::Memory::MF_READ | sys::Memory::MF_EXEC); 1338a6f3554SLang Hames if (ec) { 1348a6f3554SLang Hames if (ErrMsg) { 1358a6f3554SLang Hames *ErrMsg = ec.message(); 1368a6f3554SLang Hames } 1378a6f3554SLang Hames return true; 1388a6f3554SLang Hames } 1398a6f3554SLang Hames 1408a6f3554SLang Hames // Don't allow free memory blocks to be used after setting protection flags. 1418a6f3554SLang Hames RODataMem.FreeMem.clear(); 1428a6f3554SLang Hames 1438a6f3554SLang Hames // Make read-only data memory read-only. 1448a6f3554SLang Hames ec = applyMemoryGroupPermissions(RODataMem, 1458a6f3554SLang Hames sys::Memory::MF_READ | sys::Memory::MF_EXEC); 1468a6f3554SLang Hames if (ec) { 1478a6f3554SLang Hames if (ErrMsg) { 1488a6f3554SLang Hames *ErrMsg = ec.message(); 1498a6f3554SLang Hames } 1508a6f3554SLang Hames return true; 1518a6f3554SLang Hames } 1528a6f3554SLang Hames 1538a6f3554SLang Hames // Read-write data memory already has the correct permissions 1548a6f3554SLang Hames 1558a6f3554SLang Hames // Some platforms with separate data cache and instruction cache require 1568a6f3554SLang Hames // explicit cache flush, otherwise JIT code manipulations (like resolved 1578a6f3554SLang Hames // relocations) will get to the data cache but not to the instruction cache. 1588a6f3554SLang Hames invalidateInstructionCache(); 1598a6f3554SLang Hames 1608a6f3554SLang Hames return false; 1618a6f3554SLang Hames } 1628a6f3554SLang Hames 163*94f181a4SKeno Fischer static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) { 164*94f181a4SKeno Fischer static const size_t PageSize = sys::Process::getPageSize(); 165*94f181a4SKeno Fischer 166*94f181a4SKeno Fischer size_t StartOverlap = 167*94f181a4SKeno Fischer (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize; 168*94f181a4SKeno Fischer 169*94f181a4SKeno Fischer size_t TrimmedSize = M.size(); 170*94f181a4SKeno Fischer TrimmedSize -= StartOverlap; 171*94f181a4SKeno Fischer TrimmedSize -= TrimmedSize % PageSize; 172*94f181a4SKeno Fischer 173*94f181a4SKeno Fischer sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), TrimmedSize); 174*94f181a4SKeno Fischer 175*94f181a4SKeno Fischer assert(((uintptr_t)Trimmed.base() % PageSize) == 0); 176*94f181a4SKeno Fischer assert((Trimmed.size() % PageSize) == 0); 177*94f181a4SKeno Fischer assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size()); 178*94f181a4SKeno Fischer 179*94f181a4SKeno Fischer return Trimmed; 180*94f181a4SKeno Fischer } 181*94f181a4SKeno Fischer 182*94f181a4SKeno Fischer 1838a6f3554SLang Hames std::error_code 1848a6f3554SLang Hames SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, 1858a6f3554SLang Hames unsigned Permissions) { 18617433bd1SKeno Fischer for (sys::MemoryBlock &MB : MemGroup.PendingMem) 187efeddcc5SBenjamin Kramer if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions)) 188efeddcc5SBenjamin Kramer return EC; 1898a6f3554SLang Hames 190*94f181a4SKeno Fischer MemGroup.PendingMem.clear(); 191*94f181a4SKeno Fischer 192*94f181a4SKeno Fischer // Now go through free blocks and trim any of them that don't span the entire 193*94f181a4SKeno Fischer // page because one of the pending blocks may have overlapped it. 194*94f181a4SKeno Fischer for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { 195*94f181a4SKeno Fischer FreeMB.Free = trimBlockToPageSize(FreeMB.Free); 196*94f181a4SKeno Fischer // We cleared the PendingMem list, so all these pointers are now invalid 197*94f181a4SKeno Fischer FreeMB.PendingPrefixIndex = (unsigned)-1; 198*94f181a4SKeno Fischer } 199*94f181a4SKeno Fischer 200*94f181a4SKeno Fischer // Remove all blocks which are now empty 201*94f181a4SKeno Fischer MemGroup.FreeMem.erase( 202*94f181a4SKeno Fischer std::remove_if(MemGroup.FreeMem.begin(), MemGroup.FreeMem.end(), 203*94f181a4SKeno Fischer [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }), 204*94f181a4SKeno Fischer MemGroup.FreeMem.end()); 205*94f181a4SKeno Fischer 2068a6f3554SLang Hames return std::error_code(); 2078a6f3554SLang Hames } 2088a6f3554SLang Hames 2098a6f3554SLang Hames void SectionMemoryManager::invalidateInstructionCache() { 21017433bd1SKeno Fischer for (sys::MemoryBlock &Block : CodeMem.PendingMem) 211efeddcc5SBenjamin Kramer sys::Memory::InvalidateInstructionCache(Block.base(), Block.size()); 2128a6f3554SLang Hames } 2138a6f3554SLang Hames 2148a6f3554SLang Hames SectionMemoryManager::~SectionMemoryManager() { 21517433bd1SKeno Fischer for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) { 216efeddcc5SBenjamin Kramer for (sys::MemoryBlock &Block : Group->AllocatedMem) 217efeddcc5SBenjamin Kramer sys::Memory::releaseMappedMemory(Block); 21817433bd1SKeno Fischer } 2198a6f3554SLang Hames } 2208a6f3554SLang Hames 2218a6f3554SLang Hames } // namespace llvm 222