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