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" 188a6f3554SLang Hames 198a6f3554SLang Hames namespace llvm { 208a6f3554SLang Hames 218a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, 228a6f3554SLang Hames unsigned Alignment, 238a6f3554SLang Hames unsigned SectionID, 248a6f3554SLang Hames StringRef SectionName, 258a6f3554SLang Hames bool IsReadOnly) { 268a6f3554SLang Hames if (IsReadOnly) 278a6f3554SLang Hames return allocateSection(RODataMem, Size, Alignment); 288a6f3554SLang Hames return allocateSection(RWDataMem, Size, Alignment); 298a6f3554SLang Hames } 308a6f3554SLang Hames 318a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, 328a6f3554SLang Hames unsigned Alignment, 338a6f3554SLang Hames unsigned SectionID, 348a6f3554SLang Hames StringRef SectionName) { 358a6f3554SLang Hames return allocateSection(CodeMem, Size, Alignment); 368a6f3554SLang Hames } 378a6f3554SLang Hames 388a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, 398a6f3554SLang Hames uintptr_t Size, 408a6f3554SLang Hames unsigned Alignment) { 418a6f3554SLang Hames if (!Alignment) 428a6f3554SLang Hames Alignment = 16; 438a6f3554SLang Hames 448a6f3554SLang Hames assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); 458a6f3554SLang Hames 468a6f3554SLang Hames uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1); 478a6f3554SLang Hames uintptr_t Addr = 0; 488a6f3554SLang Hames 498a6f3554SLang Hames // Look in the list of free memory regions and use a block there if one 508a6f3554SLang Hames // is available. 51*efeddcc5SBenjamin Kramer for (sys::MemoryBlock &MB : MemGroup.FreeMem) { 528a6f3554SLang Hames if (MB.size() >= RequiredSize) { 538a6f3554SLang Hames Addr = (uintptr_t)MB.base(); 548a6f3554SLang Hames uintptr_t EndOfBlock = Addr + MB.size(); 558a6f3554SLang Hames // Align the address. 568a6f3554SLang Hames Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 578a6f3554SLang Hames // Store cutted free memory block. 58*efeddcc5SBenjamin Kramer MB = sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size); 598a6f3554SLang Hames return (uint8_t*)Addr; 608a6f3554SLang Hames } 618a6f3554SLang Hames } 628a6f3554SLang Hames 638a6f3554SLang Hames // No pre-allocated free block was large enough. Allocate a new memory region. 648a6f3554SLang Hames // Note that all sections get allocated as read-write. The permissions will 658a6f3554SLang Hames // be updated later based on memory group. 668a6f3554SLang Hames // 678a6f3554SLang Hames // FIXME: It would be useful to define a default allocation size (or add 688a6f3554SLang Hames // it as a constructor parameter) to minimize the number of allocations. 698a6f3554SLang Hames // 708a6f3554SLang Hames // FIXME: Initialize the Near member for each memory group to avoid 718a6f3554SLang Hames // interleaving. 728a6f3554SLang Hames std::error_code ec; 738a6f3554SLang Hames sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize, 748a6f3554SLang Hames &MemGroup.Near, 758a6f3554SLang Hames sys::Memory::MF_READ | 768a6f3554SLang Hames sys::Memory::MF_WRITE, 778a6f3554SLang Hames ec); 788a6f3554SLang Hames if (ec) { 798a6f3554SLang Hames // FIXME: Add error propagation to the interface. 808a6f3554SLang Hames return nullptr; 818a6f3554SLang Hames } 828a6f3554SLang Hames 838a6f3554SLang Hames // Save this address as the basis for our next request 848a6f3554SLang Hames MemGroup.Near = MB; 858a6f3554SLang Hames 868a6f3554SLang Hames MemGroup.AllocatedMem.push_back(MB); 878a6f3554SLang Hames Addr = (uintptr_t)MB.base(); 888a6f3554SLang Hames uintptr_t EndOfBlock = Addr + MB.size(); 898a6f3554SLang Hames 908a6f3554SLang Hames // Align the address. 918a6f3554SLang Hames Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 928a6f3554SLang Hames 938a6f3554SLang Hames // The allocateMappedMemory may allocate much more memory than we need. In 948a6f3554SLang Hames // this case, we store the unused memory as a free memory block. 958a6f3554SLang Hames unsigned FreeSize = EndOfBlock-Addr-Size; 968a6f3554SLang Hames if (FreeSize > 16) 978a6f3554SLang Hames MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); 988a6f3554SLang Hames 998a6f3554SLang Hames // Return aligned address 1008a6f3554SLang Hames return (uint8_t*)Addr; 1018a6f3554SLang Hames } 1028a6f3554SLang Hames 1038a6f3554SLang Hames bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) 1048a6f3554SLang Hames { 1058a6f3554SLang Hames // FIXME: Should in-progress permissions be reverted if an error occurs? 1068a6f3554SLang Hames std::error_code ec; 1078a6f3554SLang Hames 1088a6f3554SLang Hames // Don't allow free memory blocks to be used after setting protection flags. 1098a6f3554SLang Hames CodeMem.FreeMem.clear(); 1108a6f3554SLang Hames 1118a6f3554SLang Hames // Make code memory executable. 1128a6f3554SLang Hames ec = applyMemoryGroupPermissions(CodeMem, 1138a6f3554SLang Hames sys::Memory::MF_READ | sys::Memory::MF_EXEC); 1148a6f3554SLang Hames if (ec) { 1158a6f3554SLang Hames if (ErrMsg) { 1168a6f3554SLang Hames *ErrMsg = ec.message(); 1178a6f3554SLang Hames } 1188a6f3554SLang Hames return true; 1198a6f3554SLang Hames } 1208a6f3554SLang Hames 1218a6f3554SLang Hames // Don't allow free memory blocks to be used after setting protection flags. 1228a6f3554SLang Hames RODataMem.FreeMem.clear(); 1238a6f3554SLang Hames 1248a6f3554SLang Hames // Make read-only data memory read-only. 1258a6f3554SLang Hames ec = applyMemoryGroupPermissions(RODataMem, 1268a6f3554SLang Hames sys::Memory::MF_READ | sys::Memory::MF_EXEC); 1278a6f3554SLang Hames if (ec) { 1288a6f3554SLang Hames if (ErrMsg) { 1298a6f3554SLang Hames *ErrMsg = ec.message(); 1308a6f3554SLang Hames } 1318a6f3554SLang Hames return true; 1328a6f3554SLang Hames } 1338a6f3554SLang Hames 1348a6f3554SLang Hames // Read-write data memory already has the correct permissions 1358a6f3554SLang Hames 1368a6f3554SLang Hames // Some platforms with separate data cache and instruction cache require 1378a6f3554SLang Hames // explicit cache flush, otherwise JIT code manipulations (like resolved 1388a6f3554SLang Hames // relocations) will get to the data cache but not to the instruction cache. 1398a6f3554SLang Hames invalidateInstructionCache(); 1408a6f3554SLang Hames 1418a6f3554SLang Hames return false; 1428a6f3554SLang Hames } 1438a6f3554SLang Hames 1448a6f3554SLang Hames std::error_code 1458a6f3554SLang Hames SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, 1468a6f3554SLang Hames unsigned Permissions) { 1478a6f3554SLang Hames 148*efeddcc5SBenjamin Kramer for (sys::MemoryBlock &MB : MemGroup.AllocatedMem) 149*efeddcc5SBenjamin Kramer if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions)) 150*efeddcc5SBenjamin Kramer return EC; 1518a6f3554SLang Hames 1528a6f3554SLang Hames return std::error_code(); 1538a6f3554SLang Hames } 1548a6f3554SLang Hames 1558a6f3554SLang Hames void SectionMemoryManager::invalidateInstructionCache() { 156*efeddcc5SBenjamin Kramer for (sys::MemoryBlock &Block : CodeMem.AllocatedMem) 157*efeddcc5SBenjamin Kramer sys::Memory::InvalidateInstructionCache(Block.base(), Block.size()); 1588a6f3554SLang Hames } 1598a6f3554SLang Hames 1608a6f3554SLang Hames SectionMemoryManager::~SectionMemoryManager() { 161*efeddcc5SBenjamin Kramer for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) 162*efeddcc5SBenjamin Kramer for (sys::MemoryBlock &Block : Group->AllocatedMem) 163*efeddcc5SBenjamin Kramer sys::Memory::releaseMappedMemory(Block); 1648a6f3554SLang Hames } 1658a6f3554SLang Hames 1668a6f3554SLang Hames } // namespace llvm 1678a6f3554SLang Hames 168