1 //===----- EPCGenericRTDyldMemoryManager.cpp - EPC-bbasde MemMgr -----===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h"
10 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
11 #include "llvm/Support/Alignment.h"
12 #include "llvm/Support/FormatVariadic.h"
14 #define DEBUG_TYPE "orc"
16 using namespace llvm::orc::shared
;
21 Expected
<std::unique_ptr
<EPCGenericRTDyldMemoryManager
>>
22 EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols(
23 ExecutorProcessControl
&EPC
) {
25 if (auto Err
= EPC
.getBootstrapSymbols(
26 {{SAs
.Instance
, rt::SimpleExecutorMemoryManagerInstanceName
},
27 {SAs
.Reserve
, rt::SimpleExecutorMemoryManagerReserveWrapperName
},
28 {SAs
.Finalize
, rt::SimpleExecutorMemoryManagerFinalizeWrapperName
},
30 rt::SimpleExecutorMemoryManagerDeallocateWrapperName
},
31 {SAs
.RegisterEHFrame
, rt::RegisterEHFrameSectionWrapperName
},
32 {SAs
.DeregisterEHFrame
, rt::DeregisterEHFrameSectionWrapperName
}}))
33 return std::move(Err
);
34 return std::make_unique
<EPCGenericRTDyldMemoryManager
>(EPC
, std::move(SAs
));
37 EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager(
38 ExecutorProcessControl
&EPC
, SymbolAddrs SAs
)
39 : EPC(EPC
), SAs(std::move(SAs
)) {
40 LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n");
43 EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() {
44 LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n");
46 errs() << "Destroying with existing errors:\n" << ErrMsg
<< "\n";
48 Error Err
= Error::success();
49 if (auto Err2
= EPC
.callSPSWrapper
<
50 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
>(
51 SAs
.Reserve
, Err
, SAs
.Instance
, FinalizedAllocs
)) {
52 // FIXME: Report errors through EPC once that functionality is available.
53 logAllUnhandledErrors(std::move(Err2
), errs(), "");
58 logAllUnhandledErrors(std::move(Err
), errs(), "");
61 uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection(
62 uintptr_t Size
, unsigned Alignment
, unsigned SectionID
,
63 StringRef SectionName
) {
64 std::lock_guard
<std::mutex
> Lock(M
);
66 dbgs() << "Allocator " << (void *)this << " allocating code section "
67 << SectionName
<< ": size = " << formatv("{0:x}", Size
)
68 << " bytes, alignment = " << Alignment
<< "\n";
70 auto &Seg
= Unmapped
.back().CodeAllocs
;
71 Seg
.emplace_back(Size
, Alignment
);
72 return reinterpret_cast<uint8_t *>(
73 alignAddr(Seg
.back().Contents
.get(), Align(Alignment
)));
76 uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection(
77 uintptr_t Size
, unsigned Alignment
, unsigned SectionID
,
78 StringRef SectionName
, bool IsReadOnly
) {
79 std::lock_guard
<std::mutex
> Lock(M
);
81 dbgs() << "Allocator " << (void *)this << " allocating "
82 << (IsReadOnly
? "ro" : "rw") << "-data section " << SectionName
83 << ": size = " << formatv("{0:x}", Size
) << " bytes, alignment "
84 << Alignment
<< ")\n";
88 IsReadOnly
? Unmapped
.back().RODataAllocs
: Unmapped
.back().RWDataAllocs
;
90 Seg
.emplace_back(Size
, Alignment
);
91 return reinterpret_cast<uint8_t *>(
92 alignAddr(Seg
.back().Contents
.get(), Align(Alignment
)));
95 void EPCGenericRTDyldMemoryManager::reserveAllocationSpace(
96 uintptr_t CodeSize
, Align CodeAlign
, uintptr_t RODataSize
,
97 Align RODataAlign
, uintptr_t RWDataSize
, Align RWDataAlign
) {
100 std::lock_guard
<std::mutex
> Lock(M
);
101 // If there's already an error then bail out.
105 if (CodeAlign
> EPC
.getPageSize()) {
106 ErrMsg
= "Invalid code alignment in reserveAllocationSpace";
109 if (RODataAlign
> EPC
.getPageSize()) {
110 ErrMsg
= "Invalid ro-data alignment in reserveAllocationSpace";
113 if (RWDataAlign
> EPC
.getPageSize()) {
114 ErrMsg
= "Invalid rw-data alignment in reserveAllocationSpace";
119 uint64_t TotalSize
= 0;
120 TotalSize
+= alignTo(CodeSize
, EPC
.getPageSize());
121 TotalSize
+= alignTo(RODataSize
, EPC
.getPageSize());
122 TotalSize
+= alignTo(RWDataSize
, EPC
.getPageSize());
125 dbgs() << "Allocator " << (void *)this << " reserving "
126 << formatv("{0:x}", TotalSize
) << " bytes.\n";
129 Expected
<ExecutorAddr
> TargetAllocAddr((ExecutorAddr()));
130 if (auto Err
= EPC
.callSPSWrapper
<
131 rt::SPSSimpleExecutorMemoryManagerReserveSignature
>(
132 SAs
.Reserve
, TargetAllocAddr
, SAs
.Instance
, TotalSize
)) {
133 std::lock_guard
<std::mutex
> Lock(M
);
134 ErrMsg
= toString(std::move(Err
));
137 if (!TargetAllocAddr
) {
138 std::lock_guard
<std::mutex
> Lock(M
);
139 ErrMsg
= toString(TargetAllocAddr
.takeError());
143 std::lock_guard
<std::mutex
> Lock(M
);
144 Unmapped
.push_back(SectionAllocGroup());
145 Unmapped
.back().RemoteCode
= {
146 *TargetAllocAddr
, ExecutorAddrDiff(alignTo(CodeSize
, EPC
.getPageSize()))};
147 Unmapped
.back().RemoteROData
= {
148 Unmapped
.back().RemoteCode
.End
,
149 ExecutorAddrDiff(alignTo(RODataSize
, EPC
.getPageSize()))};
150 Unmapped
.back().RemoteRWData
= {
151 Unmapped
.back().RemoteROData
.End
,
152 ExecutorAddrDiff(alignTo(RWDataSize
, EPC
.getPageSize()))};
155 bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() {
159 void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr
,
163 dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame "
164 << formatv("[ {0:x} {1:x} ]", LoadAddr
, LoadAddr
+ Size
) << "\n";
166 std::lock_guard
<std::mutex
> Lock(M
);
167 // Bail out early if there's already an error.
171 ExecutorAddr
LA(LoadAddr
);
172 for (auto &SecAllocGroup
: llvm::reverse(Unfinalized
)) {
173 if (SecAllocGroup
.RemoteCode
.contains(LA
) ||
174 SecAllocGroup
.RemoteROData
.contains(LA
) ||
175 SecAllocGroup
.RemoteRWData
.contains(LA
)) {
176 SecAllocGroup
.UnfinalizedEHFrames
.push_back({LA
, Size
});
180 ErrMsg
= "eh-frame does not lie inside unfinalized alloc";
183 void EPCGenericRTDyldMemoryManager::deregisterEHFrames() {
184 // This is a no-op for us: We've registered a deallocation action for it.
187 void EPCGenericRTDyldMemoryManager::notifyObjectLoaded(
188 RuntimeDyld
&Dyld
, const object::ObjectFile
&Obj
) {
189 std::lock_guard
<std::mutex
> Lock(M
);
190 LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " applied mappings:\n");
191 for (auto &ObjAllocs
: Unmapped
) {
192 mapAllocsToRemoteAddrs(Dyld
, ObjAllocs
.CodeAllocs
,
193 ObjAllocs
.RemoteCode
.Start
);
194 mapAllocsToRemoteAddrs(Dyld
, ObjAllocs
.RODataAllocs
,
195 ObjAllocs
.RemoteROData
.Start
);
196 mapAllocsToRemoteAddrs(Dyld
, ObjAllocs
.RWDataAllocs
,
197 ObjAllocs
.RemoteRWData
.Start
);
198 Unfinalized
.push_back(std::move(ObjAllocs
));
203 bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string
*ErrMsg
) {
204 LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n");
206 // If there's an error then bail out here.
207 std::vector
<SectionAllocGroup
> SecAllocGroups
;
209 std::lock_guard
<std::mutex
> Lock(M
);
210 if (ErrMsg
&& !this->ErrMsg
.empty()) {
211 *ErrMsg
= std::move(this->ErrMsg
);
214 std::swap(SecAllocGroups
, Unfinalized
);
217 // Loop over unfinalized objects to make finalization requests.
218 for (auto &SecAllocGroup
: SecAllocGroups
) {
220 MemProt SegMemProts
[3] = {MemProt::Read
| MemProt::Exec
, MemProt::Read
,
221 MemProt::Read
| MemProt::Write
};
223 ExecutorAddrRange
*RemoteAddrs
[3] = {&SecAllocGroup
.RemoteCode
,
224 &SecAllocGroup
.RemoteROData
,
225 &SecAllocGroup
.RemoteRWData
};
227 std::vector
<SectionAlloc
> *SegSections
[3] = {&SecAllocGroup
.CodeAllocs
,
228 &SecAllocGroup
.RODataAllocs
,
229 &SecAllocGroup
.RWDataAllocs
};
231 tpctypes::FinalizeRequest FR
;
232 std::unique_ptr
<char[]> AggregateContents
[3];
234 for (unsigned I
= 0; I
!= 3; ++I
) {
235 FR
.Segments
.push_back({});
236 auto &Seg
= FR
.Segments
.back();
237 Seg
.RAG
= SegMemProts
[I
];
238 Seg
.Addr
= RemoteAddrs
[I
]->Start
;
239 for (auto &SecAlloc
: *SegSections
[I
]) {
240 Seg
.Size
= alignTo(Seg
.Size
, SecAlloc
.Align
);
241 Seg
.Size
+= SecAlloc
.Size
;
243 AggregateContents
[I
] = std::make_unique
<char[]>(Seg
.Size
);
244 size_t SecOffset
= 0;
245 for (auto &SecAlloc
: *SegSections
[I
]) {
246 SecOffset
= alignTo(SecOffset
, SecAlloc
.Align
);
247 memcpy(&AggregateContents
[I
][SecOffset
],
248 reinterpret_cast<const char *>(
249 alignAddr(SecAlloc
.Contents
.get(), Align(SecAlloc
.Align
))),
251 SecOffset
+= SecAlloc
.Size
;
252 // FIXME: Can we reset SecAlloc.Content here, now that it's copied into
253 // the aggregated content?
255 Seg
.Content
= {AggregateContents
[I
].get(), SecOffset
};
258 for (auto &Frame
: SecAllocGroup
.UnfinalizedEHFrames
)
259 FR
.Actions
.push_back(
261 WrapperFunctionCall::Create
<SPSArgList
<SPSExecutorAddrRange
>>(
262 SAs
.RegisterEHFrame
, Frame
)),
264 WrapperFunctionCall::Create
<SPSArgList
<SPSExecutorAddrRange
>>(
265 SAs
.DeregisterEHFrame
, Frame
))});
267 // We'll also need to make an extra allocation for the eh-frame wrapper call
269 Error FinalizeErr
= Error::success();
270 if (auto Err
= EPC
.callSPSWrapper
<
271 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature
>(
272 SAs
.Finalize
, FinalizeErr
, SAs
.Instance
, std::move(FR
))) {
273 std::lock_guard
<std::mutex
> Lock(M
);
274 this->ErrMsg
= toString(std::move(Err
));
275 dbgs() << "Serialization error: " << this->ErrMsg
<< "\n";
277 *ErrMsg
= this->ErrMsg
;
281 std::lock_guard
<std::mutex
> Lock(M
);
282 this->ErrMsg
= toString(std::move(FinalizeErr
));
283 dbgs() << "Finalization error: " << this->ErrMsg
<< "\n";
285 *ErrMsg
= this->ErrMsg
;
293 void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
294 RuntimeDyld
&Dyld
, std::vector
<SectionAlloc
> &Allocs
,
295 ExecutorAddr NextAddr
) {
296 for (auto &Alloc
: Allocs
) {
297 NextAddr
.setValue(alignTo(NextAddr
.getValue(), Alloc
.Align
));
299 dbgs() << " " << static_cast<void *>(Alloc
.Contents
.get()) << " -> "
300 << format("0x%016" PRIx64
, NextAddr
.getValue()) << "\n";
302 Dyld
.mapSectionAddress(reinterpret_cast<const void *>(alignAddr(
303 Alloc
.Contents
.get(), Align(Alloc
.Align
))),
304 NextAddr
.getValue());
305 Alloc
.RemoteAddr
= NextAddr
;
306 // Only advance NextAddr if it was non-null to begin with,
307 // otherwise leave it as null.
309 NextAddr
+= ExecutorAddrDiff(Alloc
.Size
);
313 } // end namespace orc
314 } // end namespace llvm