DynamicLibrary.cpp revision 008a5f515aca0412db4eb9c572c6a9aef956f39e
1//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This header file implements the operating system DynamicLibrary concept.
11//
12// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/ADT/StringMap.h"
17#include "llvm/ADT/DenseSet.h"
18#include "llvm/Support/DynamicLibrary.h"
19#include "llvm/Support/Mutex.h"
20#include "llvm/Config/config.h"
21#include <cstdio>
22#include <cstring>
23
24// Collection of symbol name/value pairs to be searched prior to any libraries.
25static llvm::StringMap<void *> *ExplicitSymbols = 0;
26
27namespace {
28
29struct ExplicitSymbolsDeleter {
30  ~ExplicitSymbolsDeleter() {
31    delete ExplicitSymbols;
32  }
33};
34
35}
36
37static ExplicitSymbolsDeleter Dummy;
38
39
40static llvm::sys::SmartMutex<true>& getMutex() {
41  static llvm::sys::SmartMutex<true> HandlesMutex;
42  return HandlesMutex;
43}
44
45void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
46                                          void *symbolValue) {
47  SmartScopedLock<true> lock(getMutex());
48  if (ExplicitSymbols == 0)
49    ExplicitSymbols = new llvm::StringMap<void*>();
50  (*ExplicitSymbols)[symbolName] = symbolValue;
51}
52
53char llvm::sys::DynamicLibrary::Invalid = 0;
54
55#ifdef LLVM_ON_WIN32
56
57#include "Windows/DynamicLibrary.inc"
58
59#else
60
61#if HAVE_DLFCN_H
62#include <dlfcn.h>
63using namespace llvm;
64using namespace llvm::sys;
65
66//===----------------------------------------------------------------------===//
67//=== WARNING: Implementation here must contain only TRULY operating system
68//===          independent code.
69//===----------------------------------------------------------------------===//
70
71static DenseSet<void *> *OpenedHandles = 0;
72
73DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
74                                                   std::string *errMsg) {
75  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
76  if (handle == 0) {
77    if (errMsg) *errMsg = dlerror();
78    return DynamicLibrary();
79  }
80
81#ifdef __CYGWIN__
82  // Cygwin searches symbols only in the main
83  // with the handle of dlopen(NULL, RTLD_GLOBAL).
84  if (filename == NULL)
85    handle = RTLD_DEFAULT;
86#endif
87
88  SmartScopedLock<true> lock(getMutex());
89  if (OpenedHandles == 0)
90    OpenedHandles = new DenseSet<void *>();
91
92  // If we've already loaded this library, dlclose() the handle in order to
93  // keep the internal refcount at +1.
94  if (!OpenedHandles->insert(handle).second)
95    dlclose(handle);
96
97  return DynamicLibrary(handle);
98}
99
100void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
101  if (!isValid())
102    return NULL;
103  return dlsym(Data, symbolName);
104}
105
106#else
107
108using namespace llvm;
109using namespace llvm::sys;
110
111DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
112                                                   std::string *errMsg) {
113  if (errMsg) *errMsg = "dlopen() not supported on this platform";
114  return DynamicLibrary();
115}
116
117void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
118  return NULL;
119}
120
121#endif
122
123namespace llvm {
124void *SearchForAddressOfSpecialSymbol(const char* symbolName);
125}
126
127void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
128  SmartScopedLock<true> Lock(getMutex());
129
130  // First check symbols added via AddSymbol().
131  if (ExplicitSymbols) {
132    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
133
134    if (i != ExplicitSymbols->end())
135      return i->second;
136  }
137
138#if HAVE_DLFCN_H
139  // Now search the libraries.
140  if (OpenedHandles) {
141    for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
142         E = OpenedHandles->end(); I != E; ++I) {
143      //lt_ptr ptr = lt_dlsym(*I, symbolName);
144      void *ptr = dlsym(*I, symbolName);
145      if (ptr) {
146        return ptr;
147      }
148    }
149  }
150#endif
151
152  if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
153    return Result;
154
155// This macro returns the address of a well-known, explicit symbol
156#define EXPLICIT_SYMBOL(SYM) \
157   if (!strcmp(symbolName, #SYM)) return &SYM
158
159// On linux we have a weird situation. The stderr/out/in symbols are both
160// macros and global variables because of standards requirements. So, we
161// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
162#if defined(__linux__)
163  {
164    EXPLICIT_SYMBOL(stderr);
165    EXPLICIT_SYMBOL(stdout);
166    EXPLICIT_SYMBOL(stdin);
167  }
168#else
169  // For everything else, we want to check to make sure the symbol isn't defined
170  // as a macro before using EXPLICIT_SYMBOL.
171  {
172#ifndef stdin
173    EXPLICIT_SYMBOL(stdin);
174#endif
175#ifndef stdout
176    EXPLICIT_SYMBOL(stdout);
177#endif
178#ifndef stderr
179    EXPLICIT_SYMBOL(stderr);
180#endif
181  }
182#endif
183#undef EXPLICIT_SYMBOL
184
185  return 0;
186}
187
188#endif // LLVM_ON_WIN32
189