xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/SectionMemoryManager.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1 //===- SectionMemoryManager.h - Memory manager for MCJIT/RtDyld -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the declaration of a section-based memory manager used by
10 // the MCJIT execution engine and RuntimeDyld.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H
15 #define LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H
16 
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
19 #include "llvm/Support/Memory.h"
20 #include <cstdint>
21 #include <string>
22 #include <system_error>
23 
24 namespace llvm {
25 
26 /// This is a simple memory manager which implements the methods called by
27 /// the RuntimeDyld class to allocate memory for section-based loading of
28 /// objects, usually those generated by the MCJIT execution engine.
29 ///
30 /// This memory manager allocates all section memory as read-write.  The
31 /// RuntimeDyld will copy JITed section memory into these allocated blocks
32 /// and perform any necessary linking and relocations.
33 ///
34 /// Any client using this memory manager MUST ensure that section-specific
35 /// page permissions have been applied before attempting to execute functions
36 /// in the JITed object.  Permissions can be applied either by calling
37 /// MCJIT::finalizeObject or by calling SectionMemoryManager::finalizeMemory
38 /// directly.  Clients of MCJIT should call MCJIT::finalizeObject.
39 class SectionMemoryManager : public RTDyldMemoryManager {
40 public:
41   /// This enum describes the various reasons to allocate pages from
42   /// allocateMappedMemory.
43   enum class AllocationPurpose {
44     Code,
45     ROData,
46     RWData,
47   };
48 
49   /// Implementations of this interface are used by SectionMemoryManager to
50   /// request pages from the operating system.
51   class MemoryMapper {
52   public:
53     /// This method attempts to allocate \p NumBytes bytes of virtual memory for
54     /// \p Purpose.  \p NearBlock may point to an existing allocation, in which
55     /// case an attempt is made to allocate more memory near the existing block.
56     /// The actual allocated address is not guaranteed to be near the requested
57     /// address.  \p Flags is used to set the initial protection flags for the
58     /// block of the memory.  \p EC [out] returns an object describing any error
59     /// that occurs.
60     ///
61     /// This method may allocate more than the number of bytes requested.  The
62     /// actual number of bytes allocated is indicated in the returned
63     /// MemoryBlock.
64     ///
65     /// The start of the allocated block must be aligned with the system
66     /// allocation granularity (64K on Windows, page size on Linux).  If the
67     /// address following \p NearBlock is not so aligned, it will be rounded up
68     /// to the next allocation granularity boundary.
69     ///
70     /// \r a non-null MemoryBlock if the function was successful, otherwise a
71     /// null MemoryBlock with \p EC describing the error.
72     virtual sys::MemoryBlock
73     allocateMappedMemory(AllocationPurpose Purpose, size_t NumBytes,
74                          const sys::MemoryBlock *const NearBlock,
75                          unsigned Flags, std::error_code &EC) = 0;
76 
77     /// This method sets the protection flags for a block of memory to the state
78     /// specified by \p Flags.  The behavior is not specified if the memory was
79     /// not allocated using the allocateMappedMemory method.
80     /// \p Block describes the memory block to be protected.
81     /// \p Flags specifies the new protection state to be assigned to the block.
82     ///
83     /// If \p Flags is MF_WRITE, the actual behavior varies with the operating
84     /// system (i.e. MF_READ | MF_WRITE on Windows) and the target architecture
85     /// (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
86     ///
87     /// \r error_success if the function was successful, or an error_code
88     /// describing the failure if an error occurred.
89     virtual std::error_code protectMappedMemory(const sys::MemoryBlock &Block,
90                                                 unsigned Flags) = 0;
91 
92     /// This method releases a block of memory that was allocated with the
93     /// allocateMappedMemory method. It should not be used to release any memory
94     /// block allocated any other way.
95     /// \p Block describes the memory to be released.
96     ///
97     /// \r error_success if the function was successful, or an error_code
98     /// describing the failure if an error occurred.
99     virtual std::error_code releaseMappedMemory(sys::MemoryBlock &M) = 0;
100 
101     virtual ~MemoryMapper();
102   };
103 
104   /// Creates a SectionMemoryManager instance with \p MM as the associated
105   /// memory mapper.  If \p MM is nullptr then a default memory mapper is used
106   /// that directly calls into the operating system.
107   SectionMemoryManager(MemoryMapper *MM = nullptr);
108   SectionMemoryManager(const SectionMemoryManager &) = delete;
109   void operator=(const SectionMemoryManager &) = delete;
110   ~SectionMemoryManager() override;
111 
112   /// Allocates a memory block of (at least) the given size suitable for
113   /// executable code.
114   ///
115   /// The value of \p Alignment must be a power of two.  If \p Alignment is zero
116   /// a default alignment of 16 will be used.
117   uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
118                                unsigned SectionID,
119                                StringRef SectionName) override;
120 
121   /// Allocates a memory block of (at least) the given size suitable for
122   /// executable code.
123   ///
124   /// The value of \p Alignment must be a power of two.  If \p Alignment is zero
125   /// a default alignment of 16 will be used.
126   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
127                                unsigned SectionID, StringRef SectionName,
128                                bool isReadOnly) override;
129 
130   /// Update section-specific memory permissions and other attributes.
131   ///
132   /// This method is called when object loading is complete and section page
133   /// permissions can be applied.  It is up to the memory manager implementation
134   /// to decide whether or not to act on this method.  The memory manager will
135   /// typically allocate all sections as read-write and then apply specific
136   /// permissions when this method is called.  Code sections cannot be executed
137   /// until this function has been called.  In addition, any cache coherency
138   /// operations needed to reliably use the memory are also performed.
139   ///
140   /// \returns true if an error occurred, false otherwise.
141   bool finalizeMemory(std::string *ErrMsg = nullptr) override;
142 
143   /// Invalidate instruction cache for code sections.
144   ///
145   /// Some platforms with separate data cache and instruction cache require
146   /// explicit cache flush, otherwise JIT code manipulations (like resolved
147   /// relocations) will get to the data cache but not to the instruction cache.
148   ///
149   /// This method is called from finalizeMemory.
150   virtual void invalidateInstructionCache();
151 
152 private:
153   struct FreeMemBlock {
154     // The actual block of free memory
155     sys::MemoryBlock Free;
156     // If there is a pending allocation from the same reservation right before
157     // this block, store it's index in PendingMem, to be able to update the
158     // pending region if part of this block is allocated, rather than having to
159     // create a new one
160     unsigned PendingPrefixIndex;
161   };
162 
163   struct MemoryGroup {
164     // PendingMem contains all blocks of memory (subblocks of AllocatedMem)
165     // which have not yet had their permissions applied, but have been given
166     // out to the user. FreeMem contains all block of memory, which have
167     // neither had their permissions applied, nor been given out to the user.
168     SmallVector<sys::MemoryBlock, 16> PendingMem;
169     SmallVector<FreeMemBlock, 16> FreeMem;
170 
171     // All memory blocks that have been requested from the system
172     SmallVector<sys::MemoryBlock, 16> AllocatedMem;
173 
174     sys::MemoryBlock Near;
175   };
176 
177   uint8_t *allocateSection(AllocationPurpose Purpose, uintptr_t Size,
178                            unsigned Alignment);
179 
180   std::error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup,
181                                               unsigned Permissions);
182 
183   void anchor() override;
184 
185   MemoryGroup CodeMem;
186   MemoryGroup RWDataMem;
187   MemoryGroup RODataMem;
188   MemoryMapper *MMapper;
189   std::unique_ptr<MemoryMapper> OwnedMMapper;
190 };
191 
192 } // end namespace llvm
193 
194 #endif // LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H
195