1 | //===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- 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 provides the UNIX specific implementation of DynamicLibrary. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) |
14 | #include <dlfcn.h> |
15 | |
16 | DynamicLibrary::HandleSet::~HandleSet() { |
17 | // Close the libraries in reverse order. |
18 | for (void *Handle : llvm::reverse(C&: Handles)) |
19 | ::dlclose(handle: Handle); |
20 | if (Process) |
21 | ::dlclose(handle: Process); |
22 | |
23 | // llvm_shutdown called, Return to default |
24 | DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; |
25 | } |
26 | |
27 | void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { |
28 | void *Handle = ::dlopen(file: File, RTLD_LAZY | RTLD_GLOBAL); |
29 | if (!Handle) { |
30 | if (Err) |
31 | *Err = ::dlerror(); |
32 | return &DynamicLibrary::Invalid; |
33 | } |
34 | |
35 | #ifdef __CYGWIN__ |
36 | // Cygwin searches symbols only in the main |
37 | // with the handle of dlopen(NULL, RTLD_GLOBAL). |
38 | if (!File) |
39 | Handle = RTLD_DEFAULT; |
40 | #endif |
41 | |
42 | return Handle; |
43 | } |
44 | |
45 | void DynamicLibrary::HandleSet::DLClose(void *Handle) { ::dlclose(handle: Handle); } |
46 | |
47 | void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { |
48 | return ::dlsym(handle: Handle, name: Symbol); |
49 | } |
50 | |
51 | #else // !HAVE_DLOPEN |
52 | |
53 | DynamicLibrary::HandleSet::~HandleSet() {} |
54 | |
55 | void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { |
56 | if (Err) |
57 | *Err = "dlopen() not supported on this platform" ; |
58 | return &Invalid; |
59 | } |
60 | |
61 | void DynamicLibrary::HandleSet::DLClose(void *Handle) {} |
62 | |
63 | void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { |
64 | return nullptr; |
65 | } |
66 | |
67 | #endif |
68 | |
69 | // Must declare the symbols in the global namespace. |
70 | static void *DoSearch(const char *SymbolName) { |
71 | #define EXPLICIT_SYMBOL(SYM) \ |
72 | extern void *SYM; \ |
73 | if (!strcmp(SymbolName, #SYM)) \ |
74 | return (void *)&SYM |
75 | |
76 | // If this is darwin, it has some funky issues, try to solve them here. Some |
77 | // important symbols are marked 'private external' which doesn't allow |
78 | // SearchForAddressOfSymbol to find them. As such, we special case them here, |
79 | // there is only a small handful of them. |
80 | |
81 | #ifdef __APPLE__ |
82 | { |
83 | // __eprintf is sometimes used for assert() handling on x86. |
84 | // |
85 | // FIXME: Currently disabled when using Clang, as we don't always have our |
86 | // runtime support libraries available. |
87 | #ifndef __clang__ |
88 | #ifdef __i386__ |
89 | EXPLICIT_SYMBOL(__eprintf); |
90 | #endif |
91 | #endif |
92 | } |
93 | #endif |
94 | |
95 | #ifdef __CYGWIN__ |
96 | { |
97 | EXPLICIT_SYMBOL(_alloca); |
98 | EXPLICIT_SYMBOL(__main); |
99 | } |
100 | #endif |
101 | |
102 | #undef EXPLICIT_SYMBOL |
103 | |
104 | // This macro returns the address of a well-known, explicit symbol |
105 | #define EXPLICIT_SYMBOL(SYM) \ |
106 | if (!strcmp(SymbolName, #SYM)) \ |
107 | return &SYM |
108 | |
109 | // Under glibc we have a weird situation. The stderr/out/in symbols are both |
110 | // macros and global variables because of standards requirements. So, we |
111 | // boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. |
112 | #if defined(__GLIBC__) |
113 | { |
114 | EXPLICIT_SYMBOL(stderr); |
115 | EXPLICIT_SYMBOL(stdout); |
116 | EXPLICIT_SYMBOL(stdin); |
117 | } |
118 | #else |
119 | // For everything else, we want to check to make sure the symbol isn't defined |
120 | // as a macro before using EXPLICIT_SYMBOL. |
121 | { |
122 | #ifndef stdin |
123 | EXPLICIT_SYMBOL(stdin); |
124 | #endif |
125 | #ifndef stdout |
126 | EXPLICIT_SYMBOL(stdout); |
127 | #endif |
128 | #ifndef stderr |
129 | EXPLICIT_SYMBOL(stderr); |
130 | #endif |
131 | } |
132 | #endif |
133 | #undef EXPLICIT_SYMBOL |
134 | |
135 | return nullptr; |
136 | } |
137 | |