1 | //===- elfnix_platform.cpp ------------------------------------------------===// |
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 code required to load the rest of the ELF-on-*IX runtime. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "elfnix_platform.h" |
14 | #include "common.h" |
15 | #include "compiler.h" |
16 | #include "error.h" |
17 | #include "wrapper_function_utils.h" |
18 | |
19 | #include <algorithm> |
20 | #include <map> |
21 | #include <mutex> |
22 | #include <sstream> |
23 | #include <string_view> |
24 | #include <unordered_map> |
25 | #include <vector> |
26 | |
27 | using namespace __orc_rt; |
28 | using namespace __orc_rt::elfnix; |
29 | |
30 | // Declare function tags for functions in the JIT process. |
31 | ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_initializers_tag) |
32 | ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_deinitializers_tag) |
33 | ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_symbol_lookup_tag) |
34 | |
35 | // eh-frame registration functions, made available via aliases |
36 | // installed by the Platform |
37 | extern "C" void __register_frame(const void *); |
38 | extern "C" void __deregister_frame(const void *); |
39 | |
40 | extern "C" void |
41 | __unw_add_dynamic_eh_frame_section(const void *) ORC_RT_WEAK_IMPORT; |
42 | extern "C" void |
43 | __unw_remove_dynamic_eh_frame_section(const void *) ORC_RT_WEAK_IMPORT; |
44 | |
45 | namespace { |
46 | |
47 | Error validatePointerSectionExtent(const char *SectionName, |
48 | const ExecutorAddrRange &SE) { |
49 | if (SE.size() % sizeof(uintptr_t)) { |
50 | std::ostringstream ErrMsg; |
51 | ErrMsg << std::hex << "Size of " << SectionName << " 0x" |
52 | << SE.Start.getValue() << " -- 0x" << SE.End.getValue() |
53 | << " is not a pointer multiple" ; |
54 | return make_error<StringError>(Args: ErrMsg.str()); |
55 | } |
56 | return Error::success(); |
57 | } |
58 | |
59 | Error runInitArray(const std::vector<ExecutorAddrRange> &InitArraySections, |
60 | const ELFNixJITDylibInitializers &MOJDIs) { |
61 | |
62 | for (const auto &ModInits : InitArraySections) { |
63 | if (auto Err = validatePointerSectionExtent(SectionName: ".init_array" , SE: ModInits)) |
64 | return Err; |
65 | |
66 | using InitFunc = void (*)(); |
67 | for (auto *Init : ModInits.toSpan<InitFunc>()) |
68 | (*Init)(); |
69 | } |
70 | |
71 | return Error::success(); |
72 | } |
73 | |
74 | struct TLSInfoEntry { |
75 | unsigned long Key = 0; |
76 | unsigned long DataAddress = 0; |
77 | }; |
78 | |
79 | struct TLSDescriptor { |
80 | void (*Resolver)(void *); |
81 | TLSInfoEntry *InfoEntry; |
82 | }; |
83 | |
84 | class ELFNixPlatformRuntimeState { |
85 | private: |
86 | struct AtExitEntry { |
87 | void (*Func)(void *); |
88 | void *Arg; |
89 | }; |
90 | |
91 | using AtExitsVector = std::vector<AtExitEntry>; |
92 | |
93 | struct PerJITDylibState { |
94 | void * = nullptr; |
95 | size_t RefCount = 0; |
96 | bool AllowReinitialization = false; |
97 | AtExitsVector AtExits; |
98 | }; |
99 | |
100 | public: |
101 | static void initialize(void *DSOHandle); |
102 | static ELFNixPlatformRuntimeState &get(); |
103 | static void destroy(); |
104 | |
105 | ELFNixPlatformRuntimeState(void *DSOHandle); |
106 | |
107 | // Delete copy and move constructors. |
108 | ELFNixPlatformRuntimeState(const ELFNixPlatformRuntimeState &) = delete; |
109 | ELFNixPlatformRuntimeState & |
110 | operator=(const ELFNixPlatformRuntimeState &) = delete; |
111 | ELFNixPlatformRuntimeState(ELFNixPlatformRuntimeState &&) = delete; |
112 | ELFNixPlatformRuntimeState &operator=(ELFNixPlatformRuntimeState &&) = delete; |
113 | |
114 | Error registerObjectSections(ELFNixPerObjectSectionsToRegister POSR); |
115 | Error deregisterObjectSections(ELFNixPerObjectSectionsToRegister POSR); |
116 | |
117 | const char *dlerror(); |
118 | void *dlopen(std::string_view Name, int Mode); |
119 | int dlclose(void *DSOHandle); |
120 | void *dlsym(void *DSOHandle, std::string_view Symbol); |
121 | |
122 | int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle); |
123 | void runAtExits(void *DSOHandle); |
124 | |
125 | /// Returns the base address of the section containing ThreadData. |
126 | Expected<std::pair<const char *, size_t>> |
127 | getThreadDataSectionFor(const char *ThreadData); |
128 | |
129 | void *getPlatformJDDSOHandle() { return PlatformJDDSOHandle; } |
130 | |
131 | private: |
132 | PerJITDylibState *getJITDylibStateByHeaderAddr(void *DSOHandle); |
133 | PerJITDylibState *getJITDylibStateByName(std::string_view Path); |
134 | PerJITDylibState & |
135 | getOrCreateJITDylibState(ELFNixJITDylibInitializers &MOJDIs); |
136 | |
137 | Error registerThreadDataSection(span<const char> ThreadDataSection); |
138 | |
139 | Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle, |
140 | std::string_view Symbol); |
141 | |
142 | Expected<ELFNixJITDylibInitializerSequence> |
143 | getJITDylibInitializersByName(std::string_view Path); |
144 | Expected<void *> dlopenInitialize(std::string_view Path, int Mode); |
145 | Error initializeJITDylib(ELFNixJITDylibInitializers &MOJDIs); |
146 | |
147 | static ELFNixPlatformRuntimeState *MOPS; |
148 | |
149 | void *PlatformJDDSOHandle; |
150 | |
151 | // Frame registration functions: |
152 | void (*registerEHFrameSection)(const void *) = nullptr; |
153 | void (*deregisterEHFrameSection)(const void *) = nullptr; |
154 | |
155 | // FIXME: Move to thread-state. |
156 | std::string DLFcnError; |
157 | |
158 | std::recursive_mutex JDStatesMutex; |
159 | std::unordered_map<void *, PerJITDylibState> JDStates; |
160 | std::unordered_map<std::string, void *> ; |
161 | |
162 | std::mutex ThreadDataSectionsMutex; |
163 | std::map<const char *, size_t> ThreadDataSections; |
164 | }; |
165 | |
166 | ELFNixPlatformRuntimeState *ELFNixPlatformRuntimeState::MOPS = nullptr; |
167 | |
168 | void ELFNixPlatformRuntimeState::initialize(void *DSOHandle) { |
169 | assert(!MOPS && "ELFNixPlatformRuntimeState should be null" ); |
170 | MOPS = new ELFNixPlatformRuntimeState(DSOHandle); |
171 | } |
172 | |
173 | ELFNixPlatformRuntimeState &ELFNixPlatformRuntimeState::get() { |
174 | assert(MOPS && "ELFNixPlatformRuntimeState not initialized" ); |
175 | return *MOPS; |
176 | } |
177 | |
178 | void ELFNixPlatformRuntimeState::destroy() { |
179 | assert(MOPS && "ELFNixPlatformRuntimeState not initialized" ); |
180 | delete MOPS; |
181 | } |
182 | |
183 | ELFNixPlatformRuntimeState::ELFNixPlatformRuntimeState(void *DSOHandle) |
184 | : PlatformJDDSOHandle(DSOHandle) { |
185 | if (__unw_add_dynamic_eh_frame_section && |
186 | __unw_remove_dynamic_eh_frame_section) { |
187 | registerEHFrameSection = __unw_add_dynamic_eh_frame_section; |
188 | deregisterEHFrameSection = __unw_remove_dynamic_eh_frame_section; |
189 | } else { |
190 | registerEHFrameSection = __register_frame; |
191 | deregisterEHFrameSection = __deregister_frame; |
192 | } |
193 | } |
194 | |
195 | Error ELFNixPlatformRuntimeState::registerObjectSections( |
196 | ELFNixPerObjectSectionsToRegister POSR) { |
197 | if (POSR.EHFrameSection.Start) |
198 | registerEHFrameSection(POSR.EHFrameSection.Start.toPtr<const char *>()); |
199 | |
200 | if (POSR.ThreadDataSection.Start) { |
201 | if (auto Err = registerThreadDataSection( |
202 | ThreadDataSection: POSR.ThreadDataSection.toSpan<const char>())) |
203 | return Err; |
204 | } |
205 | |
206 | return Error::success(); |
207 | } |
208 | |
209 | Error ELFNixPlatformRuntimeState::deregisterObjectSections( |
210 | ELFNixPerObjectSectionsToRegister POSR) { |
211 | if (POSR.EHFrameSection.Start) |
212 | deregisterEHFrameSection(POSR.EHFrameSection.Start.toPtr<const char *>()); |
213 | |
214 | return Error::success(); |
215 | } |
216 | |
217 | const char *ELFNixPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); } |
218 | |
219 | void *ELFNixPlatformRuntimeState::dlopen(std::string_view Path, int Mode) { |
220 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
221 | |
222 | // Use fast path if all JITDylibs are already loaded and don't require |
223 | // re-running initializers. |
224 | if (auto *JDS = getJITDylibStateByName(Path)) { |
225 | if (!JDS->AllowReinitialization) { |
226 | ++JDS->RefCount; |
227 | return JDS->Header; |
228 | } |
229 | } |
230 | |
231 | auto H = dlopenInitialize(Path, Mode); |
232 | if (!H) { |
233 | DLFcnError = toString(Err: H.takeError()); |
234 | return nullptr; |
235 | } |
236 | |
237 | return *H; |
238 | } |
239 | |
240 | int ELFNixPlatformRuntimeState::dlclose(void *DSOHandle) { |
241 | runAtExits(DSOHandle); |
242 | return 0; |
243 | } |
244 | |
245 | void *ELFNixPlatformRuntimeState::dlsym(void *DSOHandle, |
246 | std::string_view Symbol) { |
247 | auto Addr = lookupSymbolInJITDylib(DSOHandle, Symbol); |
248 | if (!Addr) { |
249 | DLFcnError = toString(Err: Addr.takeError()); |
250 | return 0; |
251 | } |
252 | |
253 | return Addr->toPtr<void *>(); |
254 | } |
255 | |
256 | int ELFNixPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg, |
257 | void *DSOHandle) { |
258 | // FIXME: Handle out-of-memory errors, returning -1 if OOM. |
259 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
260 | auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle); |
261 | assert(JDS && "JITDylib state not initialized" ); |
262 | JDS->AtExits.push_back(x: {.Func: F, .Arg: Arg}); |
263 | return 0; |
264 | } |
265 | |
266 | void ELFNixPlatformRuntimeState::runAtExits(void *DSOHandle) { |
267 | // FIXME: Should atexits be allowed to run concurrently with access to |
268 | // JDState? |
269 | AtExitsVector V; |
270 | { |
271 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
272 | auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle); |
273 | assert(JDS && "JITDlybi state not initialized" ); |
274 | std::swap(x&: V, y&: JDS->AtExits); |
275 | } |
276 | |
277 | while (!V.empty()) { |
278 | auto &AE = V.back(); |
279 | AE.Func(AE.Arg); |
280 | V.pop_back(); |
281 | } |
282 | } |
283 | |
284 | Expected<std::pair<const char *, size_t>> |
285 | ELFNixPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) { |
286 | std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex); |
287 | auto I = ThreadDataSections.upper_bound(x: ThreadData); |
288 | // Check that we have a valid entry conovering this address. |
289 | if (I == ThreadDataSections.begin()) |
290 | return make_error<StringError>(Args: "No thread local data section for key" ); |
291 | I = std::prev(x: I); |
292 | if (ThreadData >= I->first + I->second) |
293 | return make_error<StringError>(Args: "No thread local data section for key" ); |
294 | return *I; |
295 | } |
296 | |
297 | ELFNixPlatformRuntimeState::PerJITDylibState * |
298 | ELFNixPlatformRuntimeState::(void *DSOHandle) { |
299 | auto I = JDStates.find(x: DSOHandle); |
300 | if (I == JDStates.end()) |
301 | return nullptr; |
302 | return &I->second; |
303 | } |
304 | |
305 | ELFNixPlatformRuntimeState::PerJITDylibState * |
306 | ELFNixPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) { |
307 | // FIXME: Avoid creating string copy here. |
308 | auto I = JDNameToHeader.find(x: std::string(Name.data(), Name.size())); |
309 | if (I == JDNameToHeader.end()) |
310 | return nullptr; |
311 | void *H = I->second; |
312 | auto J = JDStates.find(x: H); |
313 | assert(J != JDStates.end() && |
314 | "JITDylib has name map entry but no header map entry" ); |
315 | return &J->second; |
316 | } |
317 | |
318 | ELFNixPlatformRuntimeState::PerJITDylibState & |
319 | ELFNixPlatformRuntimeState::getOrCreateJITDylibState( |
320 | ELFNixJITDylibInitializers &MOJDIs) { |
321 | void * = MOJDIs.DSOHandleAddress.toPtr<void *>(); |
322 | |
323 | auto &JDS = JDStates[Header]; |
324 | |
325 | // If this entry hasn't been created yet. |
326 | if (!JDS.Header) { |
327 | assert(!JDNameToHeader.count(MOJDIs.Name) && |
328 | "JITDylib has header map entry but no name map entry" ); |
329 | JDNameToHeader[MOJDIs.Name] = Header; |
330 | JDS.Header = Header; |
331 | } |
332 | |
333 | return JDS; |
334 | } |
335 | |
336 | Error ELFNixPlatformRuntimeState::registerThreadDataSection( |
337 | span<const char> ThreadDataSection) { |
338 | std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex); |
339 | auto I = ThreadDataSections.upper_bound(x: ThreadDataSection.data()); |
340 | if (I != ThreadDataSections.begin()) { |
341 | auto J = std::prev(x: I); |
342 | if (J->first + J->second > ThreadDataSection.data()) |
343 | return make_error<StringError>(Args: "Overlapping .tdata sections" ); |
344 | } |
345 | ThreadDataSections.insert( |
346 | position: I, x: std::make_pair(x: ThreadDataSection.data(), y: ThreadDataSection.size())); |
347 | return Error::success(); |
348 | } |
349 | |
350 | Expected<ExecutorAddr> |
351 | ELFNixPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle, |
352 | std::string_view Sym) { |
353 | Expected<ExecutorAddr> Result((ExecutorAddr())); |
354 | if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>( |
355 | SPSExecutorAddr, SPSString)>::call(FnTag: &__orc_rt_elfnix_symbol_lookup_tag, |
356 | Result, |
357 | Args: ExecutorAddr::fromPtr(Ptr: DSOHandle), |
358 | Args: Sym)) |
359 | return std::move(t&: Err); |
360 | return Result; |
361 | } |
362 | |
363 | Expected<ELFNixJITDylibInitializerSequence> |
364 | ELFNixPlatformRuntimeState::getJITDylibInitializersByName( |
365 | std::string_view Path) { |
366 | Expected<ELFNixJITDylibInitializerSequence> Result( |
367 | (ELFNixJITDylibInitializerSequence())); |
368 | std::string PathStr(Path.data(), Path.size()); |
369 | if (auto Err = |
370 | WrapperFunction<SPSExpected<SPSELFNixJITDylibInitializerSequence>( |
371 | SPSString)>::call(FnTag: &__orc_rt_elfnix_get_initializers_tag, Result, |
372 | Args: Path)) |
373 | return std::move(t&: Err); |
374 | return Result; |
375 | } |
376 | |
377 | Expected<void *> |
378 | ELFNixPlatformRuntimeState::dlopenInitialize(std::string_view Path, int Mode) { |
379 | // Either our JITDylib wasn't loaded, or it or one of its dependencies allows |
380 | // reinitialization. We need to call in to the JIT to see if there's any new |
381 | // work pending. |
382 | auto InitSeq = getJITDylibInitializersByName(Path); |
383 | if (!InitSeq) |
384 | return InitSeq.takeError(); |
385 | |
386 | // Init sequences should be non-empty. |
387 | if (InitSeq->empty()) |
388 | return make_error<StringError>( |
389 | Args: "__orc_rt_elfnix_get_initializers returned an " |
390 | "empty init sequence" ); |
391 | |
392 | // Otherwise register and run initializers for each JITDylib. |
393 | for (auto &MOJDIs : *InitSeq) |
394 | if (auto Err = initializeJITDylib(MOJDIs)) |
395 | return std::move(t&: Err); |
396 | |
397 | // Return the header for the last item in the list. |
398 | auto *JDS = getJITDylibStateByHeaderAddr( |
399 | DSOHandle: InitSeq->back().DSOHandleAddress.toPtr<void *>()); |
400 | assert(JDS && "Missing state entry for JD" ); |
401 | return JDS->Header; |
402 | } |
403 | |
404 | long getPriority(const std::string &name) { |
405 | auto pos = name.find_last_not_of(s: "0123456789" ); |
406 | if (pos == name.size() - 1) |
407 | return 65535; |
408 | else |
409 | return std::strtol(nptr: name.c_str() + pos + 1, endptr: nullptr, base: 10); |
410 | } |
411 | |
412 | Error ELFNixPlatformRuntimeState::initializeJITDylib( |
413 | ELFNixJITDylibInitializers &MOJDIs) { |
414 | |
415 | auto &JDS = getOrCreateJITDylibState(MOJDIs); |
416 | ++JDS.RefCount; |
417 | |
418 | using SectionList = std::vector<ExecutorAddrRange>; |
419 | std::sort(first: MOJDIs.InitSections.begin(), last: MOJDIs.InitSections.end(), |
420 | comp: [](const std::pair<std::string, SectionList> &LHS, |
421 | const std::pair<std::string, SectionList> &RHS) -> bool { |
422 | return getPriority(name: LHS.first) < getPriority(name: RHS.first); |
423 | }); |
424 | for (auto &Entry : MOJDIs.InitSections) |
425 | if (auto Err = runInitArray(InitArraySections: Entry.second, MOJDIs)) |
426 | return Err; |
427 | |
428 | return Error::success(); |
429 | } |
430 | class ELFNixPlatformRuntimeTLVManager { |
431 | public: |
432 | void *getInstance(const char *ThreadData); |
433 | |
434 | private: |
435 | std::unordered_map<const char *, char *> Instances; |
436 | std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections; |
437 | }; |
438 | |
439 | void *ELFNixPlatformRuntimeTLVManager::getInstance(const char *ThreadData) { |
440 | auto I = Instances.find(x: ThreadData); |
441 | if (I != Instances.end()) |
442 | return I->second; |
443 | auto TDS = |
444 | ELFNixPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData); |
445 | if (!TDS) { |
446 | __orc_rt_log_error(ErrMsg: toString(Err: TDS.takeError()).c_str()); |
447 | return nullptr; |
448 | } |
449 | |
450 | auto &Allocated = AllocatedSections[TDS->first]; |
451 | if (!Allocated) { |
452 | Allocated = std::make_unique<char[]>(num: TDS->second); |
453 | memcpy(dest: Allocated.get(), src: TDS->first, n: TDS->second); |
454 | } |
455 | size_t ThreadDataDelta = ThreadData - TDS->first; |
456 | assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds" ); |
457 | |
458 | char *Instance = Allocated.get() + ThreadDataDelta; |
459 | Instances[ThreadData] = Instance; |
460 | return Instance; |
461 | } |
462 | |
463 | void destroyELFNixTLVMgr(void *ELFNixTLVMgr) { |
464 | delete static_cast<ELFNixPlatformRuntimeTLVManager *>(ELFNixTLVMgr); |
465 | } |
466 | |
467 | } // end anonymous namespace |
468 | |
469 | //------------------------------------------------------------------------------ |
470 | // JIT entry points |
471 | //------------------------------------------------------------------------------ |
472 | |
473 | ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult |
474 | __orc_rt_elfnix_platform_bootstrap(char *ArgData, size_t ArgSize) { |
475 | return WrapperFunction<void(uint64_t)>::handle( |
476 | ArgData, ArgSize, |
477 | Handler: [](uint64_t &DSOHandle) { |
478 | ELFNixPlatformRuntimeState::initialize( |
479 | DSOHandle: reinterpret_cast<void *>(DSOHandle)); |
480 | }) |
481 | .release(); |
482 | } |
483 | |
484 | ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult |
485 | __orc_rt_elfnix_platform_shutdown(char *ArgData, size_t ArgSize) { |
486 | ELFNixPlatformRuntimeState::destroy(); |
487 | return WrapperFunctionResult().release(); |
488 | } |
489 | |
490 | /// Wrapper function for registering metadata on a per-object basis. |
491 | ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult |
492 | __orc_rt_elfnix_register_object_sections(char *ArgData, size_t ArgSize) { |
493 | return WrapperFunction<SPSError(SPSELFNixPerObjectSectionsToRegister)>:: |
494 | handle(ArgData, ArgSize, |
495 | Handler: [](ELFNixPerObjectSectionsToRegister &POSR) { |
496 | return ELFNixPlatformRuntimeState::get().registerObjectSections( |
497 | POSR: std::move(t&: POSR)); |
498 | }) |
499 | .release(); |
500 | } |
501 | |
502 | /// Wrapper for releasing per-object metadat. |
503 | ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult |
504 | __orc_rt_elfnix_deregister_object_sections(char *ArgData, size_t ArgSize) { |
505 | return WrapperFunction<SPSError(SPSELFNixPerObjectSectionsToRegister)>:: |
506 | handle(ArgData, ArgSize, |
507 | Handler: [](ELFNixPerObjectSectionsToRegister &POSR) { |
508 | return ELFNixPlatformRuntimeState::get() |
509 | .deregisterObjectSections(POSR: std::move(t&: POSR)); |
510 | }) |
511 | .release(); |
512 | } |
513 | |
514 | //------------------------------------------------------------------------------ |
515 | // TLV support |
516 | //------------------------------------------------------------------------------ |
517 | |
518 | ORC_RT_INTERFACE void *__orc_rt_elfnix_tls_get_addr_impl(TLSInfoEntry *D) { |
519 | auto *TLVMgr = static_cast<ELFNixPlatformRuntimeTLVManager *>( |
520 | pthread_getspecific(key: D->Key)); |
521 | if (!TLVMgr) |
522 | TLVMgr = new ELFNixPlatformRuntimeTLVManager(); |
523 | if (pthread_setspecific(key: D->Key, pointer: TLVMgr)) { |
524 | __orc_rt_log_error(ErrMsg: "Call to pthread_setspecific failed" ); |
525 | return nullptr; |
526 | } |
527 | |
528 | return TLVMgr->getInstance( |
529 | ThreadData: reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress))); |
530 | } |
531 | |
532 | ORC_RT_INTERFACE ptrdiff_t ___orc_rt_elfnix_tlsdesc_resolver_impl( |
533 | TLSDescriptor *D, const char *ThreadPointer) { |
534 | const char *TLVPtr = reinterpret_cast<const char *>( |
535 | __orc_rt_elfnix_tls_get_addr_impl(D: D->InfoEntry)); |
536 | return TLVPtr - ThreadPointer; |
537 | } |
538 | |
539 | ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult |
540 | __orc_rt_elfnix_create_pthread_key(char *ArgData, size_t ArgSize) { |
541 | return WrapperFunction<SPSExpected<uint64_t>(void)>::handle( |
542 | ArgData, ArgSize, |
543 | Handler: []() -> Expected<uint64_t> { |
544 | pthread_key_t Key; |
545 | if (int Err = pthread_key_create(key: &Key, destr_function: destroyELFNixTLVMgr)) { |
546 | __orc_rt_log_error(ErrMsg: "Call to pthread_key_create failed" ); |
547 | return make_error<StringError>(Args: strerror(errnum: Err)); |
548 | } |
549 | return static_cast<uint64_t>(Key); |
550 | }) |
551 | .release(); |
552 | } |
553 | |
554 | //------------------------------------------------------------------------------ |
555 | // cxa_atexit support |
556 | //------------------------------------------------------------------------------ |
557 | |
558 | int __orc_rt_elfnix_cxa_atexit(void (*func)(void *), void *arg, |
559 | void *dso_handle) { |
560 | return ELFNixPlatformRuntimeState::get().registerAtExit(F: func, Arg: arg, |
561 | DSOHandle: dso_handle); |
562 | } |
563 | |
564 | int __orc_rt_elfnix_atexit(void (*func)(void *)) { |
565 | auto &PlatformRTState = ELFNixPlatformRuntimeState::get(); |
566 | return ELFNixPlatformRuntimeState::get().registerAtExit( |
567 | F: func, NULL, DSOHandle: PlatformRTState.getPlatformJDDSOHandle()); |
568 | } |
569 | |
570 | void __orc_rt_elfnix_cxa_finalize(void *dso_handle) { |
571 | ELFNixPlatformRuntimeState::get().runAtExits(DSOHandle: dso_handle); |
572 | } |
573 | |
574 | //------------------------------------------------------------------------------ |
575 | // JIT'd dlfcn alternatives. |
576 | //------------------------------------------------------------------------------ |
577 | |
578 | const char *__orc_rt_elfnix_jit_dlerror() { |
579 | return ELFNixPlatformRuntimeState::get().dlerror(); |
580 | } |
581 | |
582 | void *__orc_rt_elfnix_jit_dlopen(const char *path, int mode) { |
583 | return ELFNixPlatformRuntimeState::get().dlopen(Path: path, Mode: mode); |
584 | } |
585 | |
586 | int __orc_rt_elfnix_jit_dlclose(void *dso_handle) { |
587 | return ELFNixPlatformRuntimeState::get().dlclose(DSOHandle: dso_handle); |
588 | } |
589 | |
590 | void *__orc_rt_elfnix_jit_dlsym(void *dso_handle, const char *symbol) { |
591 | return ELFNixPlatformRuntimeState::get().dlsym(DSOHandle: dso_handle, Symbol: symbol); |
592 | } |
593 | |
594 | //------------------------------------------------------------------------------ |
595 | // ELFNix Run Program |
596 | //------------------------------------------------------------------------------ |
597 | |
598 | ORC_RT_INTERFACE int64_t __orc_rt_elfnix_run_program( |
599 | const char *JITDylibName, const char *EntrySymbolName, int argc, |
600 | char *argv[]) { |
601 | using MainTy = int (*)(int, char *[]); |
602 | |
603 | void *H = __orc_rt_elfnix_jit_dlopen(path: JITDylibName, |
604 | mode: __orc_rt::elfnix::ORC_RT_RTLD_LAZY); |
605 | if (!H) { |
606 | __orc_rt_log_error(ErrMsg: __orc_rt_elfnix_jit_dlerror()); |
607 | return -1; |
608 | } |
609 | |
610 | auto *Main = |
611 | reinterpret_cast<MainTy>(__orc_rt_elfnix_jit_dlsym(dso_handle: H, symbol: EntrySymbolName)); |
612 | |
613 | if (!Main) { |
614 | __orc_rt_log_error(ErrMsg: __orc_rt_elfnix_jit_dlerror()); |
615 | return -1; |
616 | } |
617 | |
618 | int Result = Main(argc, argv); |
619 | |
620 | if (__orc_rt_elfnix_jit_dlclose(dso_handle: H) == -1) |
621 | __orc_rt_log_error(ErrMsg: __orc_rt_elfnix_jit_dlerror()); |
622 | |
623 | return Result; |
624 | } |
625 | |