1//===- JITSymbol.h - JIT symbol abstraction ---------------------*- 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// Abstraction for target process addresses. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_EXECUTIONENGINE_JITSYMBOL_H 15#define LLVM_EXECUTIONENGINE_JITSYMBOL_H 16 17#include <algorithm> 18#include <cassert> 19#include <cstddef> 20#include <cstdint> 21#include <functional> 22#include <string> 23 24#include "llvm/Support/Error.h" 25 26namespace llvm { 27 28class GlobalValue; 29 30namespace object { 31 32class BasicSymbolRef; 33 34} // end namespace object 35 36/// @brief Represents an address in the target process's address space. 37using JITTargetAddress = uint64_t; 38 39/// @brief Flags for symbols in the JIT. 40class JITSymbolFlags { 41public: 42 using UnderlyingType = uint8_t; 43 using TargetFlagsType = uint64_t; 44 45 enum FlagNames : UnderlyingType { 46 None = 0, 47 HasError = 1U << 0, 48 Weak = 1U << 1, 49 Common = 1U << 2, 50 Absolute = 1U << 3, 51 Exported = 1U << 4 52 }; 53 54 /// @brief Default-construct a JITSymbolFlags instance. 55 JITSymbolFlags() = default; 56 57 /// @brief Construct a JITSymbolFlags instance from the given flags. 58 JITSymbolFlags(FlagNames Flags) : Flags(Flags) {} 59 60 /// @brief Construct a JITSymbolFlags instance from the given flags and target 61 /// flags. 62 JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags) 63 : Flags(Flags), TargetFlags(TargetFlags) {} 64 65 /// @brief Return true if there was an error retrieving this symbol. 66 bool hasError() const { 67 return (Flags & HasError) == HasError; 68 } 69 70 /// @brief Returns true if the Weak flag is set. 71 bool isWeak() const { 72 return (Flags & Weak) == Weak; 73 } 74 75 /// @brief Returns true if the Common flag is set. 76 bool isCommon() const { 77 return (Flags & Common) == Common; 78 } 79 80 /// @brief Returns true if the symbol isn't weak or common. 81 bool isStrongDefinition() const { 82 return !isWeak() && !isCommon(); 83 } 84 85 /// @brief Returns true if the Exported flag is set. 86 bool isExported() const { 87 return (Flags & Exported) == Exported; 88 } 89 90 /// @brief Implicitly convert to the underlying flags type. 91 operator UnderlyingType&() { return Flags; } 92 93 /// @brief Implicitly convert to the underlying flags type. 94 operator const UnderlyingType&() const { return Flags; } 95 96 /// @brief Return a reference to the target-specific flags. 97 TargetFlagsType& getTargetFlags() { return TargetFlags; } 98 99 /// @brief Return a reference to the target-specific flags. 100 const TargetFlagsType& getTargetFlags() const { return TargetFlags; } 101 102 /// Construct a JITSymbolFlags value based on the flags of the given global 103 /// value. 104 static JITSymbolFlags fromGlobalValue(const GlobalValue &GV); 105 106 /// Construct a JITSymbolFlags value based on the flags of the given libobject 107 /// symbol. 108 static JITSymbolFlags fromObjectSymbol(const object::BasicSymbolRef &Symbol); 109 110private: 111 UnderlyingType Flags = None; 112 TargetFlagsType TargetFlags = 0; 113}; 114 115/// @brief ARM-specific JIT symbol flags. 116/// FIXME: This should be moved into a target-specific header. 117class ARMJITSymbolFlags { 118public: 119 ARMJITSymbolFlags() = default; 120 121 enum FlagNames { 122 None = 0, 123 Thumb = 1 << 0 124 }; 125 126 operator JITSymbolFlags::TargetFlagsType&() { return Flags; } 127 128 static ARMJITSymbolFlags fromObjectSymbol( 129 const object::BasicSymbolRef &Symbol); 130private: 131 JITSymbolFlags::TargetFlagsType Flags = 0; 132}; 133 134/// @brief Represents a symbol that has been evaluated to an address already. 135class JITEvaluatedSymbol { 136public: 137 /// @brief Create a 'null' symbol. 138 JITEvaluatedSymbol(std::nullptr_t) {} 139 140 /// @brief Create a symbol for the given address and flags. 141 JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags) 142 : Address(Address), Flags(Flags) {} 143 144 /// @brief An evaluated symbol converts to 'true' if its address is non-zero. 145 explicit operator bool() const { return Address != 0; } 146 147 /// @brief Return the address of this symbol. 148 JITTargetAddress getAddress() const { return Address; } 149 150 /// @brief Return the flags for this symbol. 151 JITSymbolFlags getFlags() const { return Flags; } 152 153private: 154 JITTargetAddress Address = 0; 155 JITSymbolFlags Flags; 156}; 157 158/// @brief Represents a symbol in the JIT. 159class JITSymbol { 160public: 161 using GetAddressFtor = std::function<Expected<JITTargetAddress>()>; 162 163 /// @brief Create a 'null' symbol, used to represent a "symbol not found" 164 /// result from a successful (non-erroneous) lookup. 165 JITSymbol(std::nullptr_t) 166 : CachedAddr(0) {} 167 168 /// @brief Create a JITSymbol representing an error in the symbol lookup 169 /// process (e.g. a network failure during a remote lookup). 170 JITSymbol(Error Err) 171 : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {} 172 173 /// @brief Create a symbol for a definition with a known address. 174 JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags) 175 : CachedAddr(Addr), Flags(Flags) {} 176 177 /// @brief Construct a JITSymbol from a JITEvaluatedSymbol. 178 JITSymbol(JITEvaluatedSymbol Sym) 179 : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {} 180 181 /// @brief Create a symbol for a definition that doesn't have a known address 182 /// yet. 183 /// @param GetAddress A functor to materialize a definition (fixing the 184 /// address) on demand. 185 /// 186 /// This constructor allows a JIT layer to provide a reference to a symbol 187 /// definition without actually materializing the definition up front. The 188 /// user can materialize the definition at any time by calling the getAddress 189 /// method. 190 JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags) 191 : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {} 192 193 JITSymbol(const JITSymbol&) = delete; 194 JITSymbol& operator=(const JITSymbol&) = delete; 195 196 JITSymbol(JITSymbol &&Other) 197 : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) { 198 if (Flags.hasError()) 199 Err = std::move(Other.Err); 200 else 201 CachedAddr = std::move(Other.CachedAddr); 202 } 203 204 JITSymbol& operator=(JITSymbol &&Other) { 205 GetAddress = std::move(Other.GetAddress); 206 Flags = std::move(Other.Flags); 207 if (Flags.hasError()) 208 Err = std::move(Other.Err); 209 else 210 CachedAddr = std::move(Other.CachedAddr); 211 return *this; 212 } 213 214 ~JITSymbol() { 215 if (Flags.hasError()) 216 Err.~Error(); 217 else 218 CachedAddr.~JITTargetAddress(); 219 } 220 221 /// @brief Returns true if the symbol exists, false otherwise. 222 explicit operator bool() const { 223 return !Flags.hasError() && (CachedAddr || GetAddress); 224 } 225 226 /// @brief Move the error field value out of this JITSymbol. 227 Error takeError() { 228 if (Flags.hasError()) 229 return std::move(Err); 230 return Error::success(); 231 } 232 233 /// @brief Get the address of the symbol in the target address space. Returns 234 /// '0' if the symbol does not exist. 235 Expected<JITTargetAddress> getAddress() { 236 assert(!Flags.hasError() && "getAddress called on error value"); 237 if (GetAddress) { 238 if (auto CachedAddrOrErr = GetAddress()) { 239 GetAddress = nullptr; 240 CachedAddr = *CachedAddrOrErr; 241 assert(CachedAddr && "Symbol could not be materialized."); 242 } else 243 return CachedAddrOrErr.takeError(); 244 } 245 return CachedAddr; 246 } 247 248 JITSymbolFlags getFlags() const { return Flags; } 249 250private: 251 GetAddressFtor GetAddress; 252 union { 253 JITTargetAddress CachedAddr; 254 Error Err; 255 }; 256 JITSymbolFlags Flags; 257}; 258 259/// \brief Symbol resolution. 260class JITSymbolResolver { 261public: 262 virtual ~JITSymbolResolver() = default; 263 264 /// This method returns the address of the specified symbol if it exists 265 /// within the logical dynamic library represented by this JITSymbolResolver. 266 /// Unlike findSymbol, queries through this interface should return addresses 267 /// for hidden symbols. 268 /// 269 /// This is of particular importance for the Orc JIT APIs, which support lazy 270 /// compilation by breaking up modules: Each of those broken out modules 271 /// must be able to resolve hidden symbols provided by the others. Clients 272 /// writing memory managers for MCJIT can usually ignore this method. 273 /// 274 /// This method will be queried by RuntimeDyld when checking for previous 275 /// definitions of common symbols. 276 virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0; 277 278 /// This method returns the address of the specified function or variable. 279 /// It is used to resolve symbols during module linking. 280 /// 281 /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will 282 /// skip all relocations for that symbol, and the client will be responsible 283 /// for handling them manually. 284 virtual JITSymbol findSymbol(const std::string &Name) = 0; 285 286private: 287 virtual void anchor(); 288}; 289 290} // end namespace llvm 291 292#endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H 293