1 //===- SectionMemoryManager.h - 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 contains the declaration of a section-based memory manager used by 11 // the MCJIT execution engine and RuntimeDyld. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H 16 #define LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H 17 18 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" 20 #include "llvm/Support/ErrorHandling.h" 21 #include "llvm/Support/Memory.h" 22 23 namespace llvm { 24 /// This is a simple memory manager which implements the methods called by 25 /// the RuntimeDyld class to allocate memory for section-based loading of 26 /// objects, usually those generated by the MCJIT execution engine. 27 /// 28 /// This memory manager allocates all section memory as read-write. The 29 /// RuntimeDyld will copy JITed section memory into these allocated blocks 30 /// and perform any necessary linking and relocations. 31 /// 32 /// Any client using this memory manager MUST ensure that section-specific 33 /// page permissions have been applied before attempting to execute functions 34 /// in the JITed object. Permissions can be applied either by calling 35 /// MCJIT::finalizeObject or by calling SectionMemoryManager::finalizeMemory 36 /// directly. Clients of MCJIT should call MCJIT::finalizeObject. 37 class SectionMemoryManager : public RTDyldMemoryManager { 38 SectionMemoryManager(const SectionMemoryManager&) = delete; 39 void operator=(const SectionMemoryManager&) = delete; 40 41 public: 42 SectionMemoryManager() { } 43 ~SectionMemoryManager() override; 44 45 /// \brief Allocates a memory block of (at least) the given size suitable for 46 /// executable code. 47 /// 48 /// The value of \p Alignment must be a power of two. If \p Alignment is zero 49 /// a default alignment of 16 will be used. 50 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, 51 unsigned SectionID, 52 StringRef SectionName) override; 53 54 /// \brief Allocates a memory block of (at least) the given size suitable for 55 /// executable code. 56 /// 57 /// The value of \p Alignment must be a power of two. If \p Alignment is zero 58 /// a default alignment of 16 will be used. 59 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 60 unsigned SectionID, StringRef SectionName, 61 bool isReadOnly) override; 62 63 /// \brief Update section-specific memory permissions and other attributes. 64 /// 65 /// This method is called when object loading is complete and section page 66 /// permissions can be applied. It is up to the memory manager implementation 67 /// to decide whether or not to act on this method. The memory manager will 68 /// typically allocate all sections as read-write and then apply specific 69 /// permissions when this method is called. Code sections cannot be executed 70 /// until this function has been called. In addition, any cache coherency 71 /// operations needed to reliably use the memory are also performed. 72 /// 73 /// \returns true if an error occurred, false otherwise. 74 bool finalizeMemory(std::string *ErrMsg = nullptr) override; 75 76 /// \brief Invalidate instruction cache for code sections. 77 /// 78 /// Some platforms with separate data cache and instruction cache require 79 /// explicit cache flush, otherwise JIT code manipulations (like resolved 80 /// relocations) will get to the data cache but not to the instruction cache. 81 /// 82 /// This method is called from finalizeMemory. 83 virtual void invalidateInstructionCache(); 84 85 private: 86 struct FreeMemBlock { 87 // The actual block of free memory 88 sys::MemoryBlock Free; 89 // If there is a pending allocation from the same reservation right before 90 // this block, store it's index in PendingMem, to be able to update the 91 // pending region if part of this block is allocated, rather than having to 92 // create a new one 93 unsigned PendingPrefixIndex; 94 }; 95 96 struct MemoryGroup { 97 // PendingMem contains all blocks of memory (subblocks of AllocatedMem) 98 // which have not yet had their permissions applied, but have been given 99 // out to the user. FreeMem contains all block of memory, which have 100 // neither had their permissions applied, nor been given out to the user. 101 SmallVector<sys::MemoryBlock, 16> PendingMem; 102 SmallVector<FreeMemBlock, 16> FreeMem; 103 104 // All memory blocks that have been requested from the system 105 SmallVector<sys::MemoryBlock, 16> AllocatedMem; 106 107 sys::MemoryBlock Near; 108 }; 109 110 uint8_t *allocateSection(MemoryGroup &MemGroup, uintptr_t Size, 111 unsigned Alignment); 112 113 std::error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup, 114 unsigned Permissions); 115 116 MemoryGroup CodeMem; 117 MemoryGroup RWDataMem; 118 MemoryGroup RODataMem; 119 }; 120 121 } 122 123 #endif // LLVM_EXECUTION_ENGINE_SECTION_MEMORY_MANAGER_H 124