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" 1894f181a4SKeno 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. 5294f181a4SKeno Fischer for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { 5394f181a4SKeno Fischer if (FreeMB.Free.size() >= RequiredSize) { 5494f181a4SKeno Fischer Addr = (uintptr_t)FreeMB.Free.base(); 5594f181a4SKeno Fischer uintptr_t EndOfBlock = Addr + FreeMB.Free.size(); 568a6f3554SLang Hames // Align the address. 578a6f3554SLang Hames Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 5894f181a4SKeno Fischer 5994f181a4SKeno Fischer if (FreeMB.PendingPrefixIndex == (unsigned)-1) { 6094f181a4SKeno Fischer // The part of the block we're giving out to the user is now pending 6194f181a4SKeno Fischer MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); 6294f181a4SKeno Fischer 6394f181a4SKeno Fischer // Remember this pending block, such that future allocations can just 6494f181a4SKeno Fischer // modify it rather than creating a new one 6594f181a4SKeno Fischer FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1; 6694f181a4SKeno Fischer } else { 6794f181a4SKeno Fischer sys::MemoryBlock &PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex]; 6894f181a4SKeno Fischer PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base()); 6994f181a4SKeno Fischer } 7094f181a4SKeno Fischer 7194f181a4SKeno Fischer // Remember how much free space is now left in this block 7294f181a4SKeno 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 10094f181a4SKeno Fischer // Remember that we allocated this memory 10194f181a4SKeno 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 10894f181a4SKeno Fischer // The part of the block we're giving out to the user is now pending 10994f181a4SKeno Fischer MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); 11094f181a4SKeno 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; 11494f181a4SKeno Fischer if (FreeSize > 16) { 11594f181a4SKeno Fischer FreeMemBlock FreeMB; 11694f181a4SKeno Fischer FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize); 11794f181a4SKeno Fischer FreeMB.PendingPrefixIndex = (unsigned)-1; 11894f181a4SKeno Fischer MemGroup.FreeMem.push_back(FreeMB); 11994f181a4SKeno 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 // Make read-only data memory read-only. 1418a6f3554SLang Hames ec = applyMemoryGroupPermissions(RODataMem, 1428a6f3554SLang Hames sys::Memory::MF_READ | sys::Memory::MF_EXEC); 1438a6f3554SLang Hames if (ec) { 1448a6f3554SLang Hames if (ErrMsg) { 1458a6f3554SLang Hames *ErrMsg = ec.message(); 1468a6f3554SLang Hames } 1478a6f3554SLang Hames return true; 1488a6f3554SLang Hames } 1498a6f3554SLang Hames 1508a6f3554SLang Hames // Read-write data memory already has the correct permissions 1518a6f3554SLang Hames 1528a6f3554SLang Hames // Some platforms with separate data cache and instruction cache require 1538a6f3554SLang Hames // explicit cache flush, otherwise JIT code manipulations (like resolved 1548a6f3554SLang Hames // relocations) will get to the data cache but not to the instruction cache. 1558a6f3554SLang Hames invalidateInstructionCache(); 1568a6f3554SLang Hames 1578a6f3554SLang Hames return false; 1588a6f3554SLang Hames } 1598a6f3554SLang Hames 16094f181a4SKeno Fischer static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) { 16194f181a4SKeno Fischer static const size_t PageSize = sys::Process::getPageSize(); 16294f181a4SKeno Fischer 16394f181a4SKeno Fischer size_t StartOverlap = 16494f181a4SKeno Fischer (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize; 16594f181a4SKeno Fischer 16694f181a4SKeno Fischer size_t TrimmedSize = M.size(); 16794f181a4SKeno Fischer TrimmedSize -= StartOverlap; 16894f181a4SKeno Fischer TrimmedSize -= TrimmedSize % PageSize; 16994f181a4SKeno Fischer 17094f181a4SKeno Fischer sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), TrimmedSize); 17194f181a4SKeno Fischer 17294f181a4SKeno Fischer assert(((uintptr_t)Trimmed.base() % PageSize) == 0); 17394f181a4SKeno Fischer assert((Trimmed.size() % PageSize) == 0); 17494f181a4SKeno Fischer assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size()); 17594f181a4SKeno Fischer 17694f181a4SKeno Fischer return Trimmed; 17794f181a4SKeno Fischer } 17894f181a4SKeno Fischer 17994f181a4SKeno Fischer 1808a6f3554SLang Hames std::error_code 1818a6f3554SLang Hames SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, 1828a6f3554SLang Hames unsigned Permissions) { 18317433bd1SKeno Fischer for (sys::MemoryBlock &MB : MemGroup.PendingMem) 184efeddcc5SBenjamin Kramer if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions)) 185efeddcc5SBenjamin Kramer return EC; 1868a6f3554SLang Hames 18794f181a4SKeno Fischer MemGroup.PendingMem.clear(); 18894f181a4SKeno Fischer 18994f181a4SKeno Fischer // Now go through free blocks and trim any of them that don't span the entire 19094f181a4SKeno Fischer // page because one of the pending blocks may have overlapped it. 19194f181a4SKeno Fischer for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { 19294f181a4SKeno Fischer FreeMB.Free = trimBlockToPageSize(FreeMB.Free); 19394f181a4SKeno Fischer // We cleared the PendingMem list, so all these pointers are now invalid 19494f181a4SKeno Fischer FreeMB.PendingPrefixIndex = (unsigned)-1; 19594f181a4SKeno Fischer } 19694f181a4SKeno Fischer 19794f181a4SKeno Fischer // Remove all blocks which are now empty 19894f181a4SKeno Fischer MemGroup.FreeMem.erase( 199*c700490fSDavid Majnemer remove_if(MemGroup.FreeMem, 20094f181a4SKeno Fischer [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }), 20194f181a4SKeno Fischer MemGroup.FreeMem.end()); 20294f181a4SKeno Fischer 2038a6f3554SLang Hames return std::error_code(); 2048a6f3554SLang Hames } 2058a6f3554SLang Hames 2068a6f3554SLang Hames void SectionMemoryManager::invalidateInstructionCache() { 20717433bd1SKeno Fischer for (sys::MemoryBlock &Block : CodeMem.PendingMem) 208efeddcc5SBenjamin Kramer sys::Memory::InvalidateInstructionCache(Block.base(), Block.size()); 2098a6f3554SLang Hames } 2108a6f3554SLang Hames 2118a6f3554SLang Hames SectionMemoryManager::~SectionMemoryManager() { 21217433bd1SKeno Fischer for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) { 213efeddcc5SBenjamin Kramer for (sys::MemoryBlock &Block : Group->AllocatedMem) 214efeddcc5SBenjamin Kramer sys::Memory::releaseMappedMemory(Block); 21517433bd1SKeno Fischer } 2168a6f3554SLang Hames } 2178a6f3554SLang Hames 2188a6f3554SLang Hames } // namespace llvm 219