LLVM  15.0.0git
RTDyldMemoryManager.cpp
Go to the documentation of this file.
1 //===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- 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 // Implementation of the runtime dynamic memory manager base class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/Config/config.h"
15 #include "llvm/Support/Compiler.h"
18 #include <cstdlib>
19 
20 #ifdef __linux__
21  // These includes used by RTDyldMemoryManager::getPointerToNamedFunction()
22  // for Glibc trickery. See comments in this function for more information.
23  #ifdef HAVE_SYS_STAT_H
24  #include <sys/stat.h>
25  #endif
26  #include <fcntl.h>
27  #include <unistd.h>
28 #endif
29 
30 namespace llvm {
31 
33 
34 #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \
35  !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
36 extern "C" void __register_frame(void *);
37 extern "C" void __deregister_frame(void *);
38 #else
39 // The building compiler does not have __(de)register_frame but
40 // it may be found at runtime in a dynamically-loaded library.
41 // For example, this happens when building LLVM with Visual C++
42 // but using the MingW runtime.
43 static void __register_frame(void *p) {
44  static bool Searched = false;
45  static void((*rf)(void *)) = 0;
46 
47  if (!Searched) {
48  Searched = true;
49  *(void **)&rf =
51  }
52  if (rf)
53  rf(p);
54 }
55 
56 static void __deregister_frame(void *p) {
57  static bool Searched = false;
58  static void((*df)(void *)) = 0;
59 
60  if (!Searched) {
61  Searched = true;
63  "__deregister_frame");
64  }
65  if (df)
66  df(p);
67 }
68 #endif
69 
70 /* libgcc and libunwind __register_frame behave differently. We use the presence
71  * of __unw_add_dynamic_fde to detect libunwind. */
72 #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
73 
74 static const char *processFDE(const char *Entry, bool isDeregister) {
75  const char *P = Entry;
76  uint32_t Length = *((const uint32_t *)P);
77  P += 4;
78  uint32_t Offset = *((const uint32_t *)P);
79  if (Offset != 0) {
80  if (isDeregister)
81  __deregister_frame(const_cast<char *>(Entry));
82  else
83  __register_frame(const_cast<char *>(Entry));
84  }
85  return P + Length;
86 }
87 
88 // This implementation handles frame registration for local targets.
89 // Memory managers for remote targets should re-implement this function
90 // and use the LoadAddr parameter.
92  size_t Size) {
93  // On OS X OS X __register_frame takes a single FDE as an argument.
94  // See http://lists.llvm.org/pipermail/llvm-dev/2013-April/061737.html
95  // and projects/libunwind/src/UnwindLevel1-gcc-ext.c.
96  const char *P = (const char *)Addr;
97  const char *End = P + Size;
98  while (P != End)
99  P = processFDE(P, false);
100 }
101 
103  size_t Size) {
104  const char *P = (const char *)Addr;
105  const char *End = P + Size;
106  while (P != End)
107  P = processFDE(P, true);
108 }
109 
110 #else
111 
113  size_t Size) {
114  // On Linux __register_frame takes a single argument:
115  // a pointer to the start of the .eh_frame section.
116 
117  // How can it find the end? Because crtendS.o is linked
118  // in and it has an .eh_frame section with four zero chars.
120 }
121 
123  size_t Size) {
125 }
126 
127 #endif
128 
130  size_t Size) {
132  EHFrames.push_back({Addr, Size});
133 }
134 
136  for (auto &Frame : EHFrames)
137  deregisterEHFramesInProcess(Frame.Addr, Frame.Size);
138  EHFrames.clear();
139 }
140 
141 static int jit_noop() {
142  return 0;
143 }
144 
145 // ARM math functions are statically linked on Android from libgcc.a, but not
146 // available at runtime for dynamic linking. On Linux these are usually placed
147 // in libgcc_s.so so can be found by normal dynamic lookup.
148 #if defined(__BIONIC__) && defined(__arm__)
149 // List of functions which are statically linked on Android and can be generated
150 // by LLVM. This is done as a nested macro which is used once to declare the
151 // imported functions with ARM_MATH_DECL and once to compare them to the
152 // user-requested symbol in getSymbolAddress with ARM_MATH_CHECK. The test
153 // assumes that all functions start with __aeabi_ and getSymbolAddress must be
154 // modified if that changes.
155 #define ARM_MATH_IMPORTS(PP) \
156  PP(__aeabi_d2f) \
157  PP(__aeabi_d2iz) \
158  PP(__aeabi_d2lz) \
159  PP(__aeabi_d2uiz) \
160  PP(__aeabi_d2ulz) \
161  PP(__aeabi_dadd) \
162  PP(__aeabi_dcmpeq) \
163  PP(__aeabi_dcmpge) \
164  PP(__aeabi_dcmpgt) \
165  PP(__aeabi_dcmple) \
166  PP(__aeabi_dcmplt) \
167  PP(__aeabi_dcmpun) \
168  PP(__aeabi_ddiv) \
169  PP(__aeabi_dmul) \
170  PP(__aeabi_dsub) \
171  PP(__aeabi_f2d) \
172  PP(__aeabi_f2iz) \
173  PP(__aeabi_f2lz) \
174  PP(__aeabi_f2uiz) \
175  PP(__aeabi_f2ulz) \
176  PP(__aeabi_fadd) \
177  PP(__aeabi_fcmpeq) \
178  PP(__aeabi_fcmpge) \
179  PP(__aeabi_fcmpgt) \
180  PP(__aeabi_fcmple) \
181  PP(__aeabi_fcmplt) \
182  PP(__aeabi_fcmpun) \
183  PP(__aeabi_fdiv) \
184  PP(__aeabi_fmul) \
185  PP(__aeabi_fsub) \
186  PP(__aeabi_i2d) \
187  PP(__aeabi_i2f) \
188  PP(__aeabi_idiv) \
189  PP(__aeabi_idivmod) \
190  PP(__aeabi_l2d) \
191  PP(__aeabi_l2f) \
192  PP(__aeabi_lasr) \
193  PP(__aeabi_ldivmod) \
194  PP(__aeabi_llsl) \
195  PP(__aeabi_llsr) \
196  PP(__aeabi_lmul) \
197  PP(__aeabi_ui2d) \
198  PP(__aeabi_ui2f) \
199  PP(__aeabi_uidiv) \
200  PP(__aeabi_uidivmod) \
201  PP(__aeabi_ul2d) \
202  PP(__aeabi_ul2f) \
203  PP(__aeabi_uldivmod)
204 
205 // Declare statically linked math functions on ARM. The function declarations
206 // here do not have the correct prototypes for each function in
207 // ARM_MATH_IMPORTS, but it doesn't matter because only the symbol addresses are
208 // needed. In particular the __aeabi_*divmod functions do not have calling
209 // conventions which match any C prototype.
210 #define ARM_MATH_DECL(name) extern "C" void name();
211 ARM_MATH_IMPORTS(ARM_MATH_DECL)
212 #undef ARM_MATH_DECL
213 #endif
214 
215 #if defined(__linux__) && defined(__GLIBC__) && \
216  (defined(__i386__) || defined(__x86_64__))
217 extern "C" LLVM_ATTRIBUTE_WEAK void __morestack();
218 #endif
219 
220 uint64_t
222  // This implementation assumes that the host program is the target.
223  // Clients generating code for a remote target should implement their own
224  // memory manager.
225 #if defined(__linux__) && defined(__GLIBC__)
226  //===--------------------------------------------------------------------===//
227  // Function stubs that are invoked instead of certain library calls
228  //
229  // Force the following functions to be linked in to anything that uses the
230  // JIT. This is a hack designed to work around the all-too-clever Glibc
231  // strategy of making these functions work differently when inlined vs. when
232  // not inlined, and hiding their real definitions in a separate archive file
233  // that the dynamic linker can't see. For more info, search for
234  // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
235  if (Name == "stat") return (uint64_t)&stat;
236  if (Name == "fstat") return (uint64_t)&fstat;
237  if (Name == "lstat") return (uint64_t)&lstat;
238  if (Name == "stat64") return (uint64_t)&stat64;
239  if (Name == "fstat64") return (uint64_t)&fstat64;
240  if (Name == "lstat64") return (uint64_t)&lstat64;
241  if (Name == "atexit") return (uint64_t)&atexit;
242  if (Name == "mknod") return (uint64_t)&mknod;
243 
244 #if defined(__i386__) || defined(__x86_64__)
245  // __morestack lives in libgcc, a static library.
246  if (&__morestack && Name == "__morestack")
247  return (uint64_t)&__morestack;
248 #endif
249 #endif // __linux__ && __GLIBC__
250 
251  // See ARM_MATH_IMPORTS definition for explanation
252 #if defined(__BIONIC__) && defined(__arm__)
253  if (Name.compare(0, 8, "__aeabi_") == 0) {
254  // Check if the user has requested any of the functions listed in
255  // ARM_MATH_IMPORTS, and if so redirect to the statically linked symbol.
256 #define ARM_MATH_CHECK(fn) if (Name == #fn) return (uint64_t)&fn;
257  ARM_MATH_IMPORTS(ARM_MATH_CHECK)
258 #undef ARM_MATH_CHECK
259  }
260 #endif
261 
262  // We should not invoke parent's ctors/dtors from generated main()!
263  // On Mingw and Cygwin, the symbol __main is resolved to
264  // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
265  // (and register wrong callee's dtors with atexit(3)).
266  // We expect ExecutionEngine::runStaticConstructorsDestructors()
267  // is called before ExecutionEngine::runFunctionAsMain() is called.
268  if (Name == "__main") return (uint64_t)&jit_noop;
269 
270  const char *NameStr = Name.c_str();
271 
272  // DynamicLibrary::SearchForAddresOfSymbol expects an unmangled 'C' symbol
273  // name so ff we're on Darwin, strip the leading '_' off.
274 #ifdef __APPLE__
275  if (NameStr[0] == '_')
276  ++NameStr;
277 #endif
278 
280 }
281 
283  bool AbortOnFailure) {
285 
286  if (!Addr && AbortOnFailure)
287  report_fatal_error(Twine("Program used external function '") + Name +
288  "' which could not be resolved!");
289 
290  return (void*)Addr;
291 }
292 
293 void RTDyldMemoryManager::anchor() {}
294 void MCJITMemoryManager::anchor() {}
295 } // namespace llvm
llvm::Check::Size
@ Size
Definition: FileCheck.h:77
llvm::RTDyldMemoryManager::registerEHFrames
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override
Register the EH frames with the runtime so that c++ exceptions work.
Definition: RTDyldMemoryManager.cpp:129
llvm::__deregister_frame
void __deregister_frame(void *)
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::jit_noop
static int jit_noop()
Definition: RTDyldMemoryManager.cpp:141
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
ErrorHandling.h
DynamicLibrary.h
llvm::RTDyldMemoryManager::getPointerToNamedFunction
virtual void * getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure=true)
This method returns the address of the specified function.
Definition: RTDyldMemoryManager.cpp:282
p
the resulting code requires compare and branches when and if * p
Definition: README.txt:396
llvm::report_fatal_error
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:143
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol
static void * SearchForAddressOfSymbol(const char *symbolName)
This function will search through all previously loaded dynamic libraries for the symbol symbolName.
Definition: DynamicLibrary.cpp:174
llvm::AMDGPU::Hwreg::Offset
Offset
Definition: SIDefines.h:416
uint64_t
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:78
llvm::RTDyldMemoryManager::deregisterEHFramesInProcess
static void deregisterEHFramesInProcess(uint8_t *Addr, size_t Size)
Deregister EH frames in the current proces.
Definition: RTDyldMemoryManager.cpp:122
llvm::RTDyldMemoryManager::~RTDyldMemoryManager
~RTDyldMemoryManager() override
uint32_t
Compiler.h
llvm::RTDyldMemoryManager::deregisterEHFrames
void deregisterEHFrames() override
Definition: RTDyldMemoryManager.cpp:135
LLVM_ATTRIBUTE_WEAK
#define LLVM_ATTRIBUTE_WEAK
Definition: Compiler.h:190
llvm::RTDyldMemoryManager::getSymbolAddressInProcess
static uint64_t getSymbolAddressInProcess(const std::string &Name)
This method returns the address of the specified function or variable in the current process.
Definition: RTDyldMemoryManager.cpp:221
RTDyldMemoryManager.h
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
llvm::RTDyldMemoryManager::getSymbolAddress
virtual uint64_t getSymbolAddress(const std::string &Name)
Legacy symbol lookup - DEPRECATED! Please override findSymbol instead.
Definition: RTDyldMemoryManager.h:85
llvm::__register_frame
void __register_frame(void *)
llvm::RTDyldMemoryManager::registerEHFramesInProcess
static void registerEHFramesInProcess(uint8_t *Addr, size_t Size)
Register EH frames in the current process.
Definition: RTDyldMemoryManager.cpp:112
llvm::RTDyldMemoryManager::EHFrames
EHFrameInfos EHFrames
Definition: RTDyldMemoryManager.h:146