[llvm] [ORC] Add Auto-Loading DyLib Feature with Symbol Resolution (PR #109913)

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 14 01:19:23 PST 2024


https://github.com/SahilPatidar updated https://github.com/llvm/llvm-project/pull/109913

>From 08a5f139bda8a784d1953a798c2268dc46789f7a Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 19 Sep 2024 17:16:45 +0530
Subject: [PATCH 1/4] [ORC] Add Auto-Loading DyLib Feature with Symbol
 Resolution

---
 .../Orc/EPCDynamicLibrarySearchGenerator.h    |   42 +
 .../Orc/EPCGenericDylibManager.h              |   12 +
 .../Orc/ExecutorProcessControl.h              |    6 +-
 .../Orc/Shared/AutoLoadDylibUtils.h           |  212 +++
 .../ExecutionEngine/Orc/Shared/OrcRTBridge.h  |    7 +
 .../Orc/TargetProcess/AutoLoadDylibLookup.h   |  155 ++
 .../SimpleExecutorDylibManager.h              |    8 +
 .../Orc/EPCDynamicLibrarySearchGenerator.cpp  |  101 +-
 .../Orc/EPCGenericDylibManager.cpp            |   35 +-
 .../Orc/ExecutorProcessControl.cpp            |    5 +
 .../Orc/Shared/OrcRTBridge.cpp                |    2 +
 .../ExecutionEngine/Orc/SimpleRemoteEPC.cpp   |   37 +-
 .../Orc/TargetProcess/AutoLoadDyLoader.cpp    | 1306 +++++++++++++++++
 .../Orc/TargetProcess/AutoLoadDylibLookUp.cpp |  575 ++++++++
 .../Orc/TargetProcess/CMakeLists.txt          |    3 +
 .../SimpleExecutorDylibManager.cpp            |   86 ++
 16 files changed, 2585 insertions(+), 7 deletions(-)
 create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
 create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h
 create mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
 create mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
index e56afe4fe656b3..901e5d05bbeb18 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
@@ -15,6 +15,7 @@
 #define LLVM_EXECUTIONENGINE_ORC_EPCDYNAMICLIBRARYSEARCHGENERATOR_H
 
 #include "llvm/ADT/FunctionExtras.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/ExecutionEngine/Orc/Core.h"
 
 namespace llvm {
@@ -71,6 +72,47 @@ class EPCDynamicLibrarySearchGenerator : public DefinitionGenerator {
   AddAbsoluteSymbolsFn AddAbsoluteSymbols;
 };
 
+class AutoLoadDynamicLibrarySearchGenerator : public DefinitionGenerator {
+public:
+  using AddAbsoluteSymbolsFn = unique_function<Error(JITDylib &, SymbolMap)>;
+
+  /// Creates an AutoLoadDynamicLibrarySearchGenerator that searches for symbols
+  /// across all currently loaded libraries. If a symbol is not found, it scans
+  /// all potential dynamic libraries (dylibs), and if the symbol is located,
+  /// the corresponding library is loaded, and the symbol's definition is
+  /// returned.
+  ///
+  /// If \p AddAbsoluteSymbols is provided, it is used to add the symbols to the
+  /// \c JITDylib; otherwise it uses JD.define(absoluteSymbols(...)).
+  AutoLoadDynamicLibrarySearchGenerator(
+      ExecutionSession &ES, AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr)
+      : EPC(ES.getExecutorProcessControl()),
+        AddAbsoluteSymbols(std::move(AddAbsoluteSymbols)) {}
+
+  /// Creates a AutoLoadDynamicLibrarySearchGenerator that searches for symbols
+  /// in the target process.
+  static Expected<std::unique_ptr<AutoLoadDynamicLibrarySearchGenerator>>
+  GetForTargetProcess(ExecutionSession &ES,
+                      AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr) {
+    return std::make_unique<AutoLoadDynamicLibrarySearchGenerator>(
+        ES, std::move(AddAbsoluteSymbols));
+  }
+
+  Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
+                      JITDylibLookupFlags JDLookupFlags,
+                      const SymbolLookupSet &Symbols) override;
+
+  Error
+  tryToResolve(SymbolNameSet CandidateSyms,
+               ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn);
+
+private:
+  ExecutorProcessControl &EPC;
+  BloomFilter GlobalFilter;
+  StringSet<> ExcludedSymbols;
+  AddAbsoluteSymbolsFn AddAbsoluteSymbols;
+};
+
 } // end namespace orc
 } // end namespace llvm
 
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
index 887147a77026e0..6bb1b40b1db933 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
@@ -34,6 +34,7 @@ class EPCGenericDylibManager {
     ExecutorAddr Instance;
     ExecutorAddr Open;
     ExecutorAddr Lookup;
+    ExecutorAddr Resolve;
   };
 
   /// Create an EPCGenericMemoryAccess instance from a given set of
@@ -70,6 +71,9 @@ class EPCGenericDylibManager {
   using SymbolLookupCompleteFn =
       unique_function<void(Expected<std::vector<ExecutorSymbolDef>>)>;
 
+  using ResolveSymbolsCompleteFn =
+      unique_function<void(Expected<ResolveResult>)>;
+
   /// Looks up symbols within the given dylib.
   void lookupAsync(tpctypes::DylibHandle H, const SymbolLookupSet &Lookup,
                    SymbolLookupCompleteFn Complete);
@@ -78,6 +82,14 @@ class EPCGenericDylibManager {
   void lookupAsync(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &Lookup,
                    SymbolLookupCompleteFn Complete);
 
+  /// Looks up symbols within the given dylib.
+  void resolveAsync(const SymbolLookupSet &Lookup,
+                           ResolveSymbolsCompleteFn Complete);
+
+  /// Looks up symbols within the given dylib.
+  void resolveAsync(const RemoteSymbolLookupSet &Lookup,
+                           ResolveSymbolsCompleteFn Complete);
+
 private:
   ExecutorProcessControl &EPC;
   SymbolAddrs SAs;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
index 5d5326c4a469ee..b5fd1c7039af3f 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
@@ -16,6 +16,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
 #include "llvm/ExecutionEngine/Orc/DylibManager.h"
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
@@ -505,7 +506,10 @@ class SelfExecutorProcessControl : public ExecutorProcessControl,
 
   void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
                           SymbolLookupCompleteFn F) override;
-
+  
+  void resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+                           ResolveSymbolsCompleteFn F) override;
+  
   std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
   char GlobalManglingPrefix = 0;
 };
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
new file mode 100644
index 00000000000000..73e8b53edf8598
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
@@ -0,0 +1,212 @@
+//===------ AutoLoadDylibUtils.h - Auto-Loading Dynamic Library -------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_AUTOLOADDYLIBUTILS_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_AUTOLOADDYLIBUTILS_H
+
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
+
+#include <math.h>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+namespace orc {
+
+namespace shared {
+using SPSBloomFilter =
+    SPSTuple<bool, uint32_t, uint32_t, uint32_t, SPSSequence<uint64_t>>;
+}
+
+constexpr uint32_t log2u(std::uint32_t n) {
+  return (n > 1) ? 1 + log2u(n >> 1) : 0;
+}
+
+class BloomFilter {
+private:
+  static constexpr int Bits = 8 * sizeof(uint64_t);
+  static constexpr float P = 0.02f;
+
+  bool Initialized = false;
+  uint32_t SymbolsCount = 0;
+  uint32_t BloomSize = 0;
+  uint32_t BloomShift = 0;
+  std::vector<uint64_t> BloomTable;
+
+  // This is a GNU implementation of hash used in bloom filter!
+  static uint32_t GNUHash(StringRef S) {
+    uint32_t H = 5381;
+    for (uint8_t C : S)
+      H = (H << 5) + H + C;
+    return H;
+  }
+  // Helper method for hash testing
+  bool TestHash(uint32_t hash) const {
+    assert(IsInitialized && "Bloom filter is not initialized!");
+    uint32_t hash2 = hash >> BloomShift;
+    uint32_t n = (hash >> log2u(Bits)) % BloomSize;
+    uint64_t mask = ((1ULL << (hash % Bits)) | (1ULL << (hash2 % Bits)));
+    return (mask & BloomTable[n]) == mask;
+  }
+
+  // Helper method to add a hash
+  void AddHash(uint32_t hash) {
+    assert(IsInitialized && "Bloom filter is not initialized!");
+    uint32_t hash2 = hash >> BloomShift;
+    uint32_t n = (hash >> log2u(Bits)) % BloomSize;
+    uint64_t mask = ((1ULL << (hash % Bits)) | (1ULL << (hash2 % Bits)));
+    BloomTable[n] |= mask;
+  }
+
+  // Resizes the Bloom filter table based on symbol count
+  void ResizeTable(uint32_t newSymbolsCount) {
+    assert(SymbolsCount == 0 && "Resize not supported after initialization!");
+    SymbolsCount = newSymbolsCount;
+    BloomSize =
+        static_cast<uint32_t>(ceil((-1.44f * SymbolsCount * log2f(P)) / Bits));
+    BloomShift = std::min(6u, log2u(SymbolsCount));
+    BloomTable.resize(BloomSize, 0);
+  }
+
+  friend class shared::SPSSerializationTraits<shared::SPSBloomFilter,
+                                              BloomFilter>;
+
+public:
+  BloomFilter() = default;
+  BloomFilter(const BloomFilter &other) noexcept
+      : Initialized(other.Initialized), SymbolsCount(other.SymbolsCount),
+        BloomSize(other.BloomSize), BloomShift(other.BloomShift),
+        BloomTable(other.BloomTable) {
+  }
+  BloomFilter &operator=(const BloomFilter &other) = delete;
+
+  BloomFilter(BloomFilter &&other) noexcept
+      : Initialized(other.Initialized), SymbolsCount(other.SymbolsCount),
+        BloomSize(other.BloomSize), BloomShift(other.BloomShift),
+        BloomTable(std::move(other.BloomTable)) {
+    other.Initialized = false;
+    other.SymbolsCount = 0;
+    other.BloomSize = 0;
+    other.BloomShift = 0;
+  }
+
+  BloomFilter &operator=(BloomFilter &&other) noexcept {
+    if (this != &other) {
+      Initialized = other.Initialized;
+      SymbolsCount = other.SymbolsCount;
+      BloomSize = other.BloomSize;
+      BloomShift = other.BloomShift;
+      BloomTable = std::move(other.BloomTable);
+
+      other.Initialized = false;
+      other.SymbolsCount = 0;
+      other.BloomSize = 0;
+      other.BloomShift = 0;
+    }
+    return *this;
+  }
+
+  void swap(BloomFilter &other) noexcept {
+    std::swap(Initialized, other.Initialized);
+    std::swap(SymbolsCount, other.SymbolsCount);
+    std::swap(BloomSize, other.BloomSize);
+    std::swap(BloomShift, other.BloomShift);
+    std::swap(BloomTable, other.BloomTable);
+  }
+
+  void Initialize(uint32_t newSymbolsCount) {
+    assert(!Initialized && "Cannot reinitialize the Bloom filter!");
+    Initialized = true;
+    ResizeTable(newSymbolsCount);
+  }
+
+  bool IsEmpty() const { return SymbolsCount == 0; }
+
+  uint32_t getSymCount() const { return SymbolsCount; }
+
+  bool IsInitialized() const { return Initialized; }
+
+  bool MayContain(uint32_t hash) const {
+    if (IsEmpty())
+      return false;
+    return TestHash(hash);
+  }
+
+  bool MayContain(StringRef symbol) const {
+    return MayContain(GNUHash(symbol));
+  }
+
+  void AddSymbol(StringRef symbol) { AddHash(GNUHash(symbol)); }
+};
+
+struct ResolveResult {
+  std::optional<BloomFilter> Filter;
+  std::vector<ExecutorSymbolDef> SymbolDef;
+};
+
+namespace shared {
+
+template <> class SPSSerializationTraits<SPSBloomFilter, BloomFilter> {
+public:
+  static size_t size(const BloomFilter &Filter) {
+    return SPSBloomFilter::AsArgList::size(
+        Filter.Initialized, Filter.SymbolsCount, Filter.BloomSize,
+        Filter.BloomShift, Filter.BloomTable);
+  }
+
+  static bool serialize(SPSOutputBuffer &OB, const BloomFilter &Filter) {
+    return SPSBloomFilter::AsArgList::serialize(
+        OB, Filter.Initialized, Filter.SymbolsCount, Filter.BloomSize,
+        Filter.BloomShift, Filter.BloomTable);
+  }
+
+  static bool deserialize(SPSInputBuffer &IB, BloomFilter &Filter) {
+    bool IsInitialized;
+    uint32_t SymbolsCount = 0, BloomSize = 0, BloomShift = 0;
+    std::vector<uint64_t> BloomTable;
+
+    if (!SPSBloomFilter::AsArgList::deserialize(
+            IB, IsInitialized, SymbolsCount, BloomSize, BloomShift, BloomTable))
+      return false;
+
+    Filter.Initialized = IsInitialized;
+    Filter.SymbolsCount = SymbolsCount;
+    Filter.BloomSize = BloomSize;
+    Filter.BloomShift = BloomShift;
+    Filter.BloomTable = std::move(BloomTable);
+
+    return true;
+  }
+};
+
+using SPSResolveResult =
+    SPSTuple<SPSOptional<SPSBloomFilter>, SPSSequence<SPSExecutorSymbolDef>>;
+template <> class SPSSerializationTraits<SPSResolveResult, ResolveResult> {
+public:
+  static size_t size(const ResolveResult &Result) {
+    return SPSResolveResult::AsArgList::size(Result.Filter, Result.SymbolDef);
+  }
+
+  static bool serialize(SPSOutputBuffer &OB, const ResolveResult &Result) {
+    return SPSResolveResult::AsArgList::serialize(OB, Result.Filter,
+                                                  Result.SymbolDef);
+  }
+
+  static bool deserialize(SPSInputBuffer &IB, ResolveResult &Result) {
+    return SPSResolveResult::AsArgList::deserialize(IB, Result.Filter,
+                                                    Result.SymbolDef);
+  }
+};
+
+} // end namespace shared
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_AUTOLOADDYLIBUTILS_H
\ No newline at end of file
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
index 0c549bcbf0130c..b834ec415820c2 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_ORCRTBRIDGE_H
 #define LLVM_EXECUTIONENGINE_ORC_SHARED_ORCRTBRIDGE_H
 
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
@@ -25,6 +26,7 @@ namespace rt {
 extern const char *SimpleExecutorDylibManagerInstanceName;
 extern const char *SimpleExecutorDylibManagerOpenWrapperName;
 extern const char *SimpleExecutorDylibManagerLookupWrapperName;
+extern const char *SimpleExecutorDylibManagerResolveWrapperName;
 
 extern const char *SimpleExecutorMemoryManagerInstanceName;
 extern const char *SimpleExecutorMemoryManagerReserveWrapperName;
@@ -59,6 +61,11 @@ using SPSSimpleExecutorDylibManagerLookupSignature =
         shared::SPSExecutorAddr, shared::SPSExecutorAddr,
         shared::SPSRemoteSymbolLookupSet);
 
+using SPSSimpleExecutorDylibManagerResolveSignature = shared::SPSExpected<
+    shared::SPSTuple<shared::SPSOptional<shared::SPSBloomFilter>,
+                     shared::SPSSequence<shared::SPSExecutorSymbolDef>>>(
+    shared::SPSExecutorAddr, shared::SPSRemoteSymbolLookupSet);
+
 using SPSSimpleExecutorMemoryManagerReserveSignature =
     shared::SPSExpected<shared::SPSExecutorAddr>(shared::SPSExecutorAddr,
                                                  uint64_t);
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h
new file mode 100644
index 00000000000000..83ad22a183f36f
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h
@@ -0,0 +1,155 @@
+//===------------ AutoLoadDylibLookup.h ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_AUTOLOADDYNAMICLIBRARY_H
+#define LLVM_EXECUTIONENGINE_ORC_AUTOLOADDYNAMICLIBRARY_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+namespace llvm {
+namespace orc {
+class DynamicLoader;
+
+#if defined(LLVM_ON_UNIX)
+const char *const kEnvDelim = ":";
+#elif defined(_WIN32)
+const char *const kEnvDelim = ";";
+#else
+#error "Unknown platform (environmental delimiter)"
+#endif
+
+class AutoLoadDynamicLibraryLookup {
+public:
+  /// Describes the library search paths.
+  struct SearchPathInfo {
+    /// The search path.
+    std::string Path;
+
+    /// True if the Path is on the LD_LIBRARY_PATH.
+    bool IsUser;
+
+    bool operator==(const SearchPathInfo &Other) const {
+      return IsUser == Other.IsUser && Path == Other.Path;
+    }
+  };
+  using SearchPathInfos = SmallVector<SearchPathInfo, 32>;
+
+private:
+  StringSet<> LoadedLibraries;
+
+  /// System's include path, get initialized at construction time.
+  SearchPathInfos SearchPaths;
+
+  DynamicLoader *Dyld = nullptr;
+
+  /// Concatenates current and system include paths to look up the filename.
+  /// Considers RPATH and RUNPATH (see: https://en.wikipedia.org/wiki/Rpath).
+  /// Returns the canonical file path or an empty string if not found.
+  std::string lookupLibInPaths(StringRef libStem,
+                               SmallVector<StringRef, 2> RPath = {},
+                               SmallVector<StringRef, 2> RunPath = {},
+                               StringRef libLoader = "") const;
+
+  /// Concatenates current and system include paths, then looks up the filename.
+  /// If not found, adds platform-specific extensions (e.g., .so, .dll, .dylib)
+  /// and retries. Considers RPATH and RUNPATH (see:
+  /// https://en.wikipedia.org/wiki/Rpath). Returns the canonical file path or
+  /// an empty string if not found.
+  std::string lookupLibMaybeAddExt(StringRef filename,
+                                   SmallVector<StringRef, 2> RPath = {},
+                                   SmallVector<StringRef, 2> RunPath = {},
+                                   StringRef libLoader = "") const;
+
+  /// On a success returns to full path to a shared object that holds the
+  /// symbol pointed by func.
+  static std::string getSymbolLocation(void *func);
+
+public:
+  AutoLoadDynamicLibraryLookup();
+  ~AutoLoadDynamicLibraryLookup();
+  AutoLoadDynamicLibraryLookup(const AutoLoadDynamicLibraryLookup &) = delete;
+  AutoLoadDynamicLibraryLookup &
+  operator=(const AutoLoadDynamicLibraryLookup &) = delete;
+
+  const SearchPathInfos &getSearchPaths() const { return SearchPaths; }
+
+  void addSearchPath(StringRef dir, bool isUser = true, bool prepend = false) {
+    if (!dir.empty()) {
+      for (auto &item : SearchPaths)
+        if (dir.equals_insensitive(item.Path))
+          return;
+      auto pos = prepend ? SearchPaths.begin() : SearchPaths.end();
+      SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser});
+    }
+  }
+
+  /// Searches for a library in current and system include paths.
+  /// Considers RPATH and RUNPATH (see: https://en.wikipedia.org/wiki/Rpath).
+  /// Returns the canonical file path or an empty string if not found.
+  std::string lookupLibrary(StringRef libStem,
+                            SmallVector<StringRef, 2> RPath = {},
+                            SmallVector<StringRef, 2> RunPath = {},
+                            StringRef libLoader = "",
+                            bool variateLibStem = true) const;
+
+  /// Add loaded library.
+  void addLoadedLib(StringRef lib);
+
+  /// Returns true if the file was a dynamic library and it was already
+  /// loaded.
+  bool isLibraryLoaded(StringRef fullPath) const;
+
+  /// Initializes the dynamic loader (dyld).
+  /// Accepts a callback to decide if certain libraries, such as those
+  /// overriding malloc, should be ignored.
+  void initializeDynamicLoader(
+      std::function<bool(StringRef)> shouldPermanentlyIgnore);
+
+  /// Finds the first unloaded shared object containing the specified symbol.
+  /// Returns the library name if found, or an empty string otherwise.
+  std::string searchLibrariesForSymbol(StringRef mangledName,
+                                       bool searchSystem = true) const;
+
+  void dump(raw_ostream *S = nullptr) const;
+
+  /// On a success returns to full path to a shared object that holds the
+  /// symbol pointed by func.
+  template <class T> static std::string getSymbolLocation(T func) {
+    static_assert(std::is_pointer<T>::value, "Must be a function pointer!");
+    return getSymbolLocation(reinterpret_cast<void *>(func));
+  }
+
+  static std::string normalizePath(StringRef path);
+
+  /// Returns true if the file is a shared library.
+  /// Also sets whether the file exists to help identify incompatible formats.
+  static bool isSharedLibrary(StringRef libFullPath, bool *exists = nullptr);
+
+  void BuildGlobalBloomFilter(BloomFilter &Filter) const;
+};
+
+enum class SplitMode {
+  PruneNonExistant, ///< Don't add non-existant paths into output
+  FailNonExistant,  ///< Fail on any non-existant paths
+  AllowNonExistant  ///< Add all paths whether they exist or not
+};
+
+bool SplitPaths(StringRef PathStr, SmallVectorImpl<StringRef> &Paths,
+                SplitMode Mode, StringRef Delim, bool Verbose = false);
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_AUTOLOADDYNAMICLIBRARY_H
\ No newline at end of file
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h
index 00fd84e3ec1426..132c3c2904732e 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h
@@ -17,11 +17,13 @@
 #define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEEXECUTORDYLIBMANAGER_H
 
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorBootstrapService.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/Error.h"
@@ -41,6 +43,8 @@ class SimpleExecutorDylibManager : public ExecutorBootstrapService {
   Expected<std::vector<ExecutorSymbolDef>>
   lookup(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &L);
 
+  Expected<ResolveResult> resolve(const RemoteSymbolLookupSet &L);
+
   Error shutdown() override;
   void addBootstrapSymbols(StringMap<ExecutorAddr> &M) override;
 
@@ -53,8 +57,12 @@ class SimpleExecutorDylibManager : public ExecutorBootstrapService {
   static llvm::orc::shared::CWrapperFunctionResult
   lookupWrapper(const char *ArgData, size_t ArgSize);
 
+  static llvm::orc::shared::CWrapperFunctionResult
+  resolveWrapper(const char *ArgData, size_t ArgSize);
+
   std::mutex M;
   DylibSet Dylibs;
+  std::optional<AutoLoadDynamicLibraryLookup> DylibLookup;
 };
 
 } // end namespace rt_bootstrap
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
index 2a93fcbf6c8c83..e58f1d1ad51c94 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
@@ -38,9 +38,9 @@ Error EPCDynamicLibrarySearchGenerator::tryToGenerate(
     return Error::success();
 
   LLVM_DEBUG({
-      dbgs() << "EPCDynamicLibrarySearchGenerator trying to generate "
-             << Symbols << "\n";
-    });
+    dbgs() << "EPCDynamicLibrarySearchGenerator trying to generate " << Symbols
+           << "\n";
+  });
 
   SymbolLookupSet LookupSymbols;
 
@@ -95,5 +95,100 @@ Error EPCDynamicLibrarySearchGenerator::tryToGenerate(
   return Error::success();
 }
 
+Error AutoLoadDynamicLibrarySearchGenerator::tryToGenerate(
+    LookupState &LS, LookupKind K, JITDylib &JD,
+    JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {
+
+  if (Symbols.empty())
+    return Error::success();
+
+  LLVM_DEBUG({
+    dbgs() << "AutoLoadDynamicLibrarySearchGenerator trying to generate "
+           << Symbols << "\n";
+  });
+
+  SymbolNameSet CandidateSyms;
+  for (auto &KV : Symbols) {
+    if (GlobalFilter.IsInitialized() && !GlobalFilter.MayContain(*KV.first) &&
+        !ExcludedSymbols.count(*KV.first))
+      continue;
+
+    CandidateSyms.insert(KV.first);
+  }
+
+  if (CandidateSyms.empty())
+    return Error::success();
+
+  auto Err = tryToResolve(CandidateSyms, [this, &JD, LS = std::move(LS),
+                                          CandidateSyms](auto Result) mutable {
+    auto &ResolveRes = Result->front();
+    bool IsFilter = GlobalFilter.IsInitialized();
+    if (!IsFilter && ResolveRes.Filter.has_value()) {
+      GlobalFilter = std::move(ResolveRes.Filter.value());
+    }
+
+    if (!Result) {
+      LLVM_DEBUG({
+        dbgs() << "AutoLoadDynamicLibrarySearchGenerator resolve failed due to "
+                  "error";
+      });
+      return LS.continueLookup(Result.takeError());
+    }
+
+    auto &Symbols = ResolveRes.SymbolDef;
+    assert(Result->size() == 1 && "Results for more than one library returned");
+    assert(Symbols.size() == CandidateSyms.size() &&
+           "Result has incorrect number of elements");
+
+    SymbolMap NewSymbols;
+    auto ResultI = Symbols.begin();
+    for (auto &S : CandidateSyms) {
+      if (ResultI->getAddress())
+        NewSymbols[S] = *ResultI;
+      else if (IsFilter)
+        ExcludedSymbols.insert(*S);
+      ++ResultI;
+    }
+
+    LLVM_DEBUG({
+      dbgs() << "AutoLoadDynamicLibrarySearchGenerator resolve returned "
+             << NewSymbols << "\n";
+    });
+
+    // If there were no resolved symbols bail out.
+    if (NewSymbols.empty())
+      return LS.continueLookup(Error::success());
+
+    // Define resolved symbols.
+    Error Err = AddAbsoluteSymbols
+                    ? AddAbsoluteSymbols(JD, std::move(NewSymbols))
+                    : JD.define(absoluteSymbols(std::move(NewSymbols)));
+
+    LS.continueLookup(std::move(Err));
+  });
+
+  return Err;
+}
+
+Error AutoLoadDynamicLibrarySearchGenerator::tryToResolve(
+    SymbolNameSet CandidateSyms,
+    ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn) {
+
+  LLVM_DEBUG({
+    dbgs() << "AutoLoadDynamicLibrarySearchGenerator trying to resolve "
+           << CandidateSyms << "\n";
+  });
+
+  SymbolLookupSet LookupSymbols;
+
+  for (auto &S : CandidateSyms) {
+    LookupSymbols.add(S, SymbolLookupFlags::WeaklyReferencedSymbol);
+  }
+
+  EPC.resolveSymbolsAsync(LookupSymbols, std::move(OnCompleteFn));
+
+  return Error::success();
+}
+
 } // end namespace orc
 } // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp
index f98b18ccd0dc74..5382c0d7e5cdd5 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp
@@ -66,7 +66,8 @@ EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(
   if (auto Err = EPC.getBootstrapSymbols(
           {{SAs.Instance, rt::SimpleExecutorDylibManagerInstanceName},
            {SAs.Open, rt::SimpleExecutorDylibManagerOpenWrapperName},
-           {SAs.Lookup, rt::SimpleExecutorDylibManagerLookupWrapperName}}))
+           {SAs.Lookup, rt::SimpleExecutorDylibManagerLookupWrapperName},
+           {SAs.Resolve, rt::SimpleExecutorDylibManagerResolveWrapperName}}))
     return std::move(Err);
   return EPCGenericDylibManager(EPC, std::move(SAs));
 }
@@ -117,5 +118,37 @@ void EPCGenericDylibManager::lookupAsync(tpctypes::DylibHandle H,
       SAs.Instance, H, Lookup);
 }
 
+void EPCGenericDylibManager::resolveAsync(const SymbolLookupSet &Lookup,
+                                          ResolveSymbolsCompleteFn Complete) {
+  EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorDylibManagerResolveSignature>(
+      SAs.Resolve,
+      [Complete = std::move(Complete)](Error SerializationErr,
+                                       Expected<ResolveResult> Result) mutable {
+        if (SerializationErr) {
+          cantFail(Result.takeError());
+          Complete(std::move(SerializationErr));
+          return;
+        }
+        Complete(std::move(Result));
+      },
+      SAs.Instance, Lookup);
+}
+
+void EPCGenericDylibManager::resolveAsync(const RemoteSymbolLookupSet &Lookup,
+                                          ResolveSymbolsCompleteFn Complete) {
+  EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorDylibManagerResolveSignature>(
+      SAs.Resolve,
+      [Complete = std::move(Complete)](Error SerializationErr,
+                                       Expected<ResolveResult> Result) mutable {
+        if (SerializationErr) {
+          cantFail(Result.takeError());
+          Complete(std::move(SerializationErr));
+          return;
+        }
+        Complete(std::move(Result));
+      },
+      SAs.Instance, Lookup);
+}
+
 } // end namespace orc
 } // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
index 2a3ede90ade0da..0df3afbf532cb8 100644
--- a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
@@ -116,6 +116,11 @@ void SelfExecutorProcessControl::lookupSymbolsAsync(
   Complete(std::move(R));
 }
 
+void SelfExecutorProcessControl::resolveSymbolsAsync(
+    ArrayRef<SymbolLookupSet> Request, ResolveSymbolsCompleteFn F) {
+  llvm_unreachable("Unsupported");
+}
+
 Expected<int32_t>
 SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr,
                                       ArrayRef<std::string> Args) {
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
index ae39b1d1bfaa9d..bb2e31346d25b6 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
@@ -18,6 +18,8 @@ const char *SimpleExecutorDylibManagerOpenWrapperName =
     "__llvm_orc_SimpleExecutorDylibManager_open_wrapper";
 const char *SimpleExecutorDylibManagerLookupWrapperName =
     "__llvm_orc_SimpleExecutorDylibManager_lookup_wrapper";
+const char *SimpleExecutorDylibManagerResolveWrapperName =
+    "__llvm_orc_SimpleExecutorDylibManager_resolve_wrapper";
 
 const char *SimpleExecutorMemoryManagerInstanceName =
     "__llvm_orc_SimpleExecutorMemoryManager_Instance";
diff --git a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
index 0f9612bae074c5..a6de6ca7fc33f5 100644
--- a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
@@ -57,11 +57,45 @@ lookupSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
                        });
 }
 
+static void
+resolveSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
+                          ArrayRef<SymbolLookupSet> Request,
+                          std::vector<ResolveResult> Result,
+                          SimpleRemoteEPC::ResolveSymbolsCompleteFn Complete) {
+  if (Request.empty())
+    return Complete(std::move(Result));
+
+  auto &Symbols = Request.front();
+  DylibMgr.resolveAsync(Symbols, [&DylibMgr, Request,
+                                  Complete = std::move(Complete),
+                                  Result = std::move(Result)](auto R) mutable {
+    if (!R)
+      return Complete(R.takeError());
+    Result.push_back({});
+    if (R->Filter.has_value())
+      Result.back().Filter.swap(R->Filter);
+
+    auto &S = R->SymbolDef;
+    auto &SymDef = Result.back().SymbolDef;
+    SymDef.reserve(S.size());
+    for (auto Addr : S)
+      SymDef.push_back(Addr);
+
+    resolveSymbolsAsyncHelper(DylibMgr, Request.drop_front(), std::move(Result),
+                              std::move(Complete));
+  });
+}
+
 void SimpleRemoteEPC::lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
                                          SymbolLookupCompleteFn Complete) {
   lookupSymbolsAsyncHelper(*EPCDylibMgr, Request, {}, std::move(Complete));
 }
 
+void SimpleRemoteEPC::resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+                                          ResolveSymbolsCompleteFn Complete) {
+  resolveSymbolsAsyncHelper(*DylibMgr, Request, {}, std::move(Complete));
+}
+
 Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,
                                              ArrayRef<std::string> Args) {
   int64_t Result = 0;
@@ -299,8 +333,7 @@ Error SimpleRemoteEPC::setup(Setup S) {
 
   // Prepare a handler for the setup packet.
   PendingCallWrapperResults[0] =
-    RunInPlace()(
-      [&](shared::WrapperFunctionResult SetupMsgBytes) {
+      RunInPlace()([&](shared::WrapperFunctionResult SetupMsgBytes) {
         if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
           EIP.set_value(
               make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
new file mode 100644
index 00000000000000..334507b6d371a9
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
@@ -0,0 +1,1306 @@
+//===---------------- DynamicLibraryManagerSymbol.cpp ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/WithColor.h"
+
+#include <algorithm>
+#include <list>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#ifdef LLVM_ON_UNIX
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif // LLVM_ON_UNIX
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#include <sys/stat.h>
+#undef LC_LOAD_DYLIB
+#undef LC_RPATH
+#endif // __APPLE__
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <libloaderapi.h> // For GetModuleFileNameA
+#include <memoryapi.h>    // For VirtualQuery
+#include <windows.h>
+#endif
+
+namespace {
+#define PATH_MAX 1024
+using BasePath = std::string;
+using namespace llvm;
+
+// // This is a GNU implementation of hash used in bloom filter!
+static uint32_t GNUHash(StringRef S) {
+  uint32_t H = 5381;
+  for (uint8_t C : S)
+    H = (H << 5) + H + C;
+  return H;
+}
+
+/// An efficient representation of a full path to a library which does not
+/// duplicate common path patterns reducing the overall memory footprint.
+///
+/// For example, `/home/.../lib/libA.so`, Path will contain a pointer
+/// to  `/home/.../lib/`
+/// will be stored and .second `libA.so`.
+/// This approach reduces the duplicate paths as at one location there may be
+/// plenty of libraries.
+struct LibraryPath {
+  const BasePath &Path;
+  std::string LibName;
+  orc::BloomFilter Filter;
+  StringSet<> Symbols;
+  // std::vector<const LibraryPath*> LibDeps;
+
+  LibraryPath(const BasePath &Path, const std::string &LibName)
+      : Path(Path), LibName(LibName) {}
+
+  bool operator==(const LibraryPath &other) const {
+    return (&Path == &other.Path || Path == other.Path) &&
+           LibName == other.LibName;
+  }
+
+  const std::string GetFullName() const {
+    SmallString<512> Vec(Path);
+    sys::path::append(Vec, StringRef(LibName));
+    return Vec.str().str();
+  }
+
+  void AddBloom(StringRef symbol) { Filter.AddSymbol(symbol); }
+
+  StringRef AddSymbol(const std::string &symbol) {
+    auto it = Symbols.insert(symbol);
+    return it.first->getKey();
+  }
+
+  bool hasBloomFilter() const { return Filter.IsInitialized(); }
+
+  bool isBloomFilterEmpty() const {
+    assert(Filter.IsInitialized() && "Bloom filter not initialized!");
+    return Filter.IsEmpty();
+  }
+
+  void InitializeBloomFilter(uint32_t newSymbolsCount) {
+    assert(!Filter.IsInitialized() && "Cannot re-initialize non-empty filter!");
+    Filter.Initialize(newSymbolsCount);
+  }
+
+  bool MayExistSymbol(StringRef symbol) const {
+    // The library had no symbols and the bloom filter is empty.
+    if (isBloomFilterEmpty())
+      return false;
+
+    return Filter.MayContain(symbol);
+  }
+
+  bool ExistSymbol(StringRef symbol) const {
+    return Symbols.find(symbol) != Symbols.end();
+  }
+};
+
+/// A helper class keeping track of loaded libraries. It implements a fast
+/// search O(1) while keeping deterministic iterability in a memory efficient
+/// way. The underlying set uses a custom hasher for better efficiency given the
+/// specific problem where the library names (LibName) are relatively short
+/// strings and the base paths (Path) are repetitive long strings.
+class LibraryPaths {
+  struct LibraryPathHashFn {
+    size_t operator()(const LibraryPath &item) const {
+      return std::hash<size_t>()(item.Path.length()) ^
+             std::hash<std::string>()(item.LibName);
+    }
+  };
+
+  std::vector<const LibraryPath *> Libs;
+  std::unordered_set<LibraryPath, LibraryPathHashFn> LibsH;
+
+public:
+  bool HasRegisteredLib(const LibraryPath &Lib) const {
+    return LibsH.count(Lib);
+  }
+
+  const LibraryPath *GetRegisteredLib(const LibraryPath &Lib) const {
+    auto search = LibsH.find(Lib);
+    if (search != LibsH.end())
+      return &(*search);
+    return nullptr;
+  }
+
+  const LibraryPath *RegisterLib(const LibraryPath &Lib) {
+    auto it = LibsH.insert(Lib);
+    assert(it.second && "Already registered!");
+    Libs.push_back(&*it.first);
+    return &*it.first;
+  }
+
+  void UnregisterLib(const LibraryPath &Lib) {
+    auto found = LibsH.find(Lib);
+    if (found == LibsH.end())
+      return;
+
+    Libs.erase(std::find(Libs.begin(), Libs.end(), &*found));
+    LibsH.erase(found);
+  }
+
+  size_t size() const {
+    assert(Libs.size() == LibsH.size());
+    return Libs.size();
+  }
+
+  const std::vector<const LibraryPath *> &GetLibraries() const { return Libs; }
+};
+
+#ifndef _WIN32
+// Cached version of system function lstat
+static inline mode_t cached_lstat(const char *path) {
+  static StringMap<mode_t> lstat_cache;
+
+  // If already cached - retun cached result
+  auto it = lstat_cache.find(path);
+  if (it != lstat_cache.end())
+    return it->second;
+
+  // If result not in cache - call system function and cache result
+  struct stat buf;
+  mode_t st_mode = (lstat(path, &buf) == -1) ? 0 : buf.st_mode;
+  lstat_cache.insert(std::pair<StringRef, mode_t>(path, st_mode));
+  return st_mode;
+}
+
+// Cached version of system function readlink
+static inline StringRef cached_readlink(const char *pathname) {
+  static StringMap<std::string> readlink_cache;
+
+  // If already cached - retun cached result
+  auto it = readlink_cache.find(pathname);
+  if (it != readlink_cache.end())
+    return StringRef(it->second);
+
+  // If result not in cache - call system function and cache result
+  char buf[PATH_MAX];
+  ssize_t len;
+  if ((len = readlink(pathname, buf, sizeof(buf))) != -1) {
+    buf[len] = '\0';
+    std::string s(buf);
+    readlink_cache.insert(std::pair<StringRef, std::string>(pathname, s));
+    return readlink_cache[pathname];
+  }
+  return "";
+}
+#endif
+
+// Cached version of system function realpath
+std::string cached_realpath(StringRef path, StringRef base_path = "",
+                            bool is_base_path_real = false,
+                            long symlooplevel = 40) {
+  if (path.empty()) {
+    errno = ENOENT;
+    return "";
+  }
+
+  if (!symlooplevel) {
+    errno = ELOOP;
+    return "";
+  }
+
+  // If already cached - retun cached result
+  static StringMap<std::pair<std::string, int>> cache;
+  bool relative_path = sys::path::is_relative(path);
+  if (!relative_path) {
+    auto it = cache.find(path);
+    if (it != cache.end()) {
+      errno = it->second.second;
+      return it->second.first;
+    }
+  }
+
+  // If result not in cache - call system function and cache result
+
+  StringRef sep(sys::path::get_separator());
+  SmallString<256> result(sep);
+#ifndef _WIN32
+  SmallVector<StringRef, 16> p;
+
+  // Relative or absolute path
+  if (relative_path) {
+    if (is_base_path_real) {
+      result.assign(base_path);
+    } else {
+      if (path[0] == '~' &&
+          (path.size() == 1 || sys::path::is_separator(path[1]))) {
+        static SmallString<128> home;
+        if (home.str().empty())
+          sys::path::home_directory(home);
+        StringRef(home).split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+      } else if (base_path.empty()) {
+        static SmallString<256> current_path;
+        if (current_path.str().empty())
+          sys::fs::current_path(current_path);
+        StringRef(current_path)
+            .split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+      } else {
+        base_path.split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+      }
+    }
+  }
+  path.split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+
+  // Handle path list items
+  for (auto item : p) {
+    if (item == ".")
+      continue; // skip "." element in "abc/./def"
+    if (item == "..") {
+      // collapse "a/b/../c" to "a/c"
+      size_t s = result.rfind(sep);
+      if (s != StringRef::npos)
+        result.resize(s);
+      if (result.empty())
+        result = sep;
+      continue;
+    }
+
+    size_t old_size = result.size();
+    sys::path::append(result, item);
+    mode_t st_mode = cached_lstat(result.c_str());
+    if (S_ISLNK(st_mode)) {
+      StringRef symlink = cached_readlink(result.c_str());
+      if (sys::path::is_relative(symlink)) {
+        result.resize(old_size);
+        result = cached_realpath(symlink, result, true, symlooplevel - 1);
+      } else {
+        result = cached_realpath(symlink, "", true, symlooplevel - 1);
+      }
+    } else if (st_mode == 0) {
+      cache.insert(std::pair<StringRef, std::pair<std::string, int>>(
+          path, std::pair<std::string, int>("", ENOENT)));
+      errno = ENOENT;
+      return "";
+    }
+  }
+#else
+  sys::fs::real_path(path, result);
+#endif
+  cache.insert(std::pair<StringRef, std::pair<std::string, int>>(
+      path, std::pair<std::string, int>(result.str().str(), errno)));
+  return result.str().str();
+}
+
+using namespace llvm;
+using namespace object;
+
+template <class ELFT>
+static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) {
+  auto DynamicEntriesOrError = Elf->dynamicEntries();
+  if (!DynamicEntriesOrError)
+    return DynamicEntriesOrError.takeError();
+
+  for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
+    if (Dyn.d_tag == ELF::DT_STRTAB) {
+      auto MappedAddrOrError = Elf->toMappedAddr(Dyn.getPtr());
+      if (!MappedAddrOrError)
+        return MappedAddrOrError.takeError();
+      return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError));
+    }
+  }
+
+  // If the dynamic segment is not present, we fall back on the sections.
+  auto SectionsOrError = Elf->sections();
+  if (!SectionsOrError)
+    return SectionsOrError.takeError();
+
+  for (const typename ELFT::Shdr &Sec : *SectionsOrError) {
+    if (Sec.sh_type == ELF::SHT_DYNSYM)
+      return Elf->getStringTableForSymtab(Sec);
+  }
+
+  return createError("dynamic string table not found");
+}
+
+static StringRef GetGnuHashSection(object::ObjectFile *file) {
+  for (auto S : file->sections()) {
+    StringRef name = cantFail(S.getName());
+    if (name == ".gnu.hash") {
+      return cantFail(S.getContents());
+    }
+  }
+  return "";
+}
+
+/// Bloom filter is a stochastic data structure which can tell us if a symbol
+/// name does not exist in a library with 100% certainty. If it tells us it
+/// exists this may not be true:
+/// https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2
+///
+/// ELF has this optimization in the new linkers by default, It is stored in the
+/// gnu.hash section of the object file.
+///
+///\returns true if the symbol may be in the library.
+static bool MayExistInElfObjectFile(object::ObjectFile *soFile, uint32_t hash) {
+  assert(soFile->isELF() && "Not ELF");
+
+  // Compute the platform bitness -- either 64 or 32.
+  const unsigned bits = 8 * soFile->getBytesInAddress();
+
+  StringRef contents = GetGnuHashSection(soFile);
+  if (contents.size() < 16)
+    // We need to search if the library doesn't have .gnu.hash section!
+    return true;
+  const char *hashContent = contents.data();
+
+  // See https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/ for .gnu.hash
+  // table layout.
+  uint32_t maskWords = *reinterpret_cast<const uint32_t *>(hashContent + 8);
+  uint32_t shift2 = *reinterpret_cast<const uint32_t *>(hashContent + 12);
+  uint32_t hash2 = hash >> shift2;
+  uint32_t n = (hash / bits) % maskWords;
+
+  const char *bloomfilter = hashContent + 16;
+  const char *hash_pos = bloomfilter + n * (bits / 8); // * (Bits / 8)
+  uint64_t word = *reinterpret_cast<const uint64_t *>(hash_pos);
+  uint64_t bitmask = ((1ULL << (hash % bits)) | (1ULL << (hash2 % bits)));
+  return (bitmask & word) == bitmask;
+}
+
+} // namespace
+
+// This function isn't referenced outside its translation unit, but it
+// can't use the "static" keyword because its address is used for
+// GetMainExecutable (since some platforms don't support taking the
+// address of main, and some platforms can't implement GetMainExecutable
+// without being given the address of a function in the main executable).
+std::string GetExecutablePath() {
+  // This just needs to be some symbol in the binary; C++ doesn't
+  // allow taking the address of ::main however.
+  return llvm::orc::AutoLoadDynamicLibraryLookup::getSymbolLocation(
+      &GetExecutablePath);
+}
+
+namespace llvm {
+namespace orc {
+class DynamicLoader {
+  struct BasePathHashFunction {
+    size_t operator()(const BasePath &item) const {
+      return std::hash<std::string>()(item);
+    }
+  };
+
+  struct BasePathEqFunction {
+    size_t operator()(const BasePath &l, const BasePath &r) const {
+      return &l == &r || l == r;
+    }
+  };
+  /// A memory efficient VectorSet. The class provides O(1) search
+  /// complexity. It is tuned to compare BasePaths first by checking the
+  /// address and then the representation which models the base path reuse.
+  class BasePaths {
+  public:
+    std::unordered_set<BasePath, BasePathHashFunction, BasePathEqFunction>
+        Paths;
+
+  public:
+    const BasePath &RegisterBasePath(const std::string &Path,
+                                     bool *WasInserted = nullptr) {
+      auto it = Paths.insert(Path);
+      if (WasInserted)
+        *WasInserted = it.second;
+
+      return *it.first;
+    }
+
+    bool Contains(StringRef Path) { return Paths.count(Path.str()); }
+  };
+
+  bool FirstRun = true;
+  bool FirstRunSysLib = true;
+  bool UseBloomFilter = true;
+  bool UseHashTable = true;
+
+  const AutoLoadDynamicLibraryLookup &AutoLoadDylibMgr;
+
+  /// The basename of `/home/.../lib/libA.so`,
+  /// BasePaths will contain `/home/.../lib/`
+  BasePaths BasePaths;
+
+  LibraryPaths Libraries;
+  LibraryPaths SysLibraries;
+  /// Contains a set of libraries which we gave to the user via ResolveSymbol
+  /// call and next time we should check if the user loaded them to avoid
+  /// useless iterations.
+  LibraryPaths QueriedLibraries;
+
+  using PermanentlyIgnoreCallbackProto = std::function<bool(StringRef)>;
+  const PermanentlyIgnoreCallbackProto ShouldPermanentlyIgnoreCallback;
+  const StringRef ExecutableFormat;
+
+  /// Scan for shared objects which are not yet loaded. They are a our symbol
+  /// resolution candidate sources.
+  /// NOTE: We only scan not loaded shared objects.
+  /// \param[in] searchSystemLibraries - whether to decent to standard system
+  ///            locations for shared objects.
+  void ScanForLibraries(bool searchSystemLibraries = false);
+
+  /// Builds a bloom filter lookup optimization.
+  void BuildBloomFilter(LibraryPath *Lib, object::ObjectFile *BinObjFile,
+                        unsigned IgnoreSymbolFlags = 0) const;
+
+  /// Looks up symbols from a an object file, representing the library.
+  ///\param[in] Lib - full path to the library.
+  ///\param[in] mangledName - the mangled name to look for.
+  ///\param[in] IgnoreSymbolFlags - The symbols to ignore upon a match.
+  ///\returns true on success.
+  bool ContainsSymbol(const LibraryPath *Lib, StringRef mangledName,
+                      unsigned IgnoreSymbolFlags = 0) const;
+
+  bool ShouldPermanentlyIgnore(StringRef FileName) const;
+  void dumpDebugInfo() const;
+
+public:
+  DynamicLoader(const AutoLoadDynamicLibraryLookup &DLM,
+                PermanentlyIgnoreCallbackProto shouldIgnore,
+                StringRef execFormat)
+      : AutoLoadDylibMgr(DLM), ShouldPermanentlyIgnoreCallback(shouldIgnore),
+        ExecutableFormat(execFormat) {}
+
+  ~DynamicLoader(){};
+
+  std::string searchLibrariesForSymbol(StringRef mangledName,
+                                       bool searchSystem);
+
+  void BuildGlobalBloomFilter(BloomFilter &Filter) const;
+};
+
+std::string RPathToStr(SmallVector<StringRef, 2> V) {
+  std::string result;
+  for (auto item : V)
+    result += item.str() + ",";
+  if (!result.empty())
+    result.pop_back();
+  return result;
+}
+
+template <class ELFT>
+void HandleDynTab(const ELFFile<ELFT> *Elf, StringRef FileName,
+                  SmallVector<StringRef, 2> &RPath,
+                  SmallVector<StringRef, 2> &RunPath,
+                  std::vector<StringRef> &Deps, bool &isPIEExecutable) {
+#define DEBUG_TYPE "Dyld:"
+  const char *Data = "";
+  if (Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf))
+    Data = StrTabOrErr.get().data();
+
+  isPIEExecutable = false;
+
+  auto DynamicEntriesOrError = Elf->dynamicEntries();
+  if (!DynamicEntriesOrError) {
+    LLVM_DEBUG(dbgs() << "Dyld: failed to read dynamic entries in"
+                      << "'" << FileName.str() << "'\n");
+    return;
+  }
+
+  for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
+    switch (Dyn.d_tag) {
+    case ELF::DT_NEEDED:
+      Deps.push_back(Data + Dyn.d_un.d_val);
+      break;
+    case ELF::DT_RPATH:
+      SplitPaths(Data + Dyn.d_un.d_val, RPath, SplitMode::AllowNonExistant,
+                 kEnvDelim, false);
+      break;
+    case ELF::DT_RUNPATH:
+      SplitPaths(Data + Dyn.d_un.d_val, RunPath, SplitMode::AllowNonExistant,
+                 kEnvDelim, false);
+      break;
+    case ELF::DT_FLAGS_1:
+      // Check if this is not a pie executable.
+      if (Dyn.d_un.d_val & ELF::DF_1_PIE)
+        isPIEExecutable = true;
+      break;
+      // (Dyn.d_tag == ELF::DT_NULL) continue;
+      // (Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER)
+    }
+  }
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::ScanForLibraries(bool searchSystemLibraries /* = false*/) {
+#define DEBUG_TYPE "Dyld:ScanForLibraries:"
+  const auto &searchPaths = AutoLoadDylibMgr.getSearchPaths();
+
+  LLVM_DEBUG({
+    dbgs() << "Dyld::ScanForLibraries: system="
+           << (searchSystemLibraries ? "true" : "false") << "\n";
+    for (const AutoLoadDynamicLibraryLookup::SearchPathInfo &Info : searchPaths)
+      dbgs() << ">>>" << Info.Path << ", "
+             << (Info.IsUser ? "user\n" : "system\n");
+  });
+
+  SmallSet<const BasePath *, 32> ScannedPaths;
+  // FileName must be always full/absolute/resolved file name.
+  std::function<void(StringRef, unsigned)> ProcessLibraryFile =
+      [&](StringRef FileName, unsigned level) {
+        LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries HandleLib:"
+                          << FileName.str() << ", level=" << level << " -> ");
+
+        StringRef FileRealPath = sys::path::parent_path(FileName);
+        StringRef FileRealName = sys::path::filename(FileName);
+        const BasePath &BaseP = BasePaths.RegisterBasePath(FileRealPath.str());
+        LibraryPath LibPath(BaseP, FileRealName.str());
+
+        if (SysLibraries.GetRegisteredLib(LibPath) ||
+            Libraries.GetRegisteredLib(LibPath)) {
+          LLVM_DEBUG(dbgs() << "Already handled!!!\n");
+          return;
+        }
+
+        if (ShouldPermanentlyIgnore(FileName)) {
+          LLVM_DEBUG(dbgs() << "PermanentlyIgnored!!!\n");
+          return;
+        }
+
+        if (searchSystemLibraries)
+          SysLibraries.RegisterLib(LibPath);
+        else
+          Libraries.RegisterLib(LibPath);
+
+        SmallVector<StringRef, 2> RPath, RunPath;
+        std::vector<StringRef> Deps;
+
+        auto ObjFileOrErr = object::ObjectFile::createObjectFile(FileName);
+        if (Error Err = ObjFileOrErr.takeError()) {
+          LLVM_DEBUG({
+            std::string Message;
+            handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+              Message += EIB.message() + "; ";
+            });
+            dbgs() << "Dyld::ScanForLibraries: Failed to read object file "
+                   << FileName.str() << " Errors: " << Message << "\n";
+          });
+          return;
+        }
+
+        object::ObjectFile *BinObjF = ObjFileOrErr.get().getBinary();
+        if (BinObjF->isELF()) {
+          bool isPIEExecutable = false;
+
+          if (const auto *ELF = dyn_cast<ELF32LEObjectFile>(BinObjF))
+            HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+                         isPIEExecutable);
+          else if (const auto *ELF = dyn_cast<ELF32BEObjectFile>(BinObjF))
+            HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+                         isPIEExecutable);
+          else if (const auto *ELF = dyn_cast<ELF64LEObjectFile>(BinObjF))
+            HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+                         isPIEExecutable);
+          else if (const auto *ELF = dyn_cast<ELF64BEObjectFile>(BinObjF))
+            HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+                         isPIEExecutable);
+
+          if (level == 0 && isPIEExecutable) {
+            if (searchSystemLibraries)
+              SysLibraries.UnregisterLib(LibPath);
+            else
+              Libraries.UnregisterLib(LibPath);
+            return;
+          }
+        } else if (BinObjF->isMachO()) {
+          MachOObjectFile *Obj = dyn_cast<MachOObjectFile>(BinObjF);
+          for (const auto &Command : Obj->load_commands()) {
+            if (Command.C.cmd == MachO::LC_LOAD_DYLIB) {
+              MachO::dylib_command dylibCmd =
+                  Obj->getDylibIDLoadCommand(Command);
+              Deps.push_back(StringRef(Command.Ptr + dylibCmd.dylib.name));
+            } else if (Command.C.cmd == MachO::LC_RPATH) {
+              MachO::rpath_command rpathCmd = Obj->getRpathCommand(Command);
+              SplitPaths(Command.Ptr + rpathCmd.path, RPath,
+                         SplitMode::AllowNonExistant, kEnvDelim, false);
+            }
+          }
+        } else if (BinObjF->isCOFF()) {
+          // TODO: Implement COFF support
+        }
+
+        LLVM_DEBUG({
+          dbgs() << "Dyld::ScanForLibraries: Deps Info:\n";
+          dbgs() << "   RPATH=" << RPathToStr(RPath) << "\n";
+          dbgs() << "   RUNPATH=" << RPathToStr(RunPath) << "\n";
+          for (size_t i = 0; i < Deps.size(); ++i)
+            dbgs() << "   Deps[" << i << "]=" << Deps[i].str() << "\n";
+        });
+
+        // Heuristics for workaround performance problems:
+        // (H1) If RPATH and RUNPATH == "" -> skip handling Deps
+        if (RPath.empty() && RunPath.empty()) {
+          LLVM_DEBUG(dbgs()
+                     << "Dyld::ScanForLibraries: Skip all deps by Heuristic1: "
+                     << FileName.str() << "\n");
+          return;
+        }
+
+        // (H2) If RPATH subset of LD_LIBRARY_PATH &&
+        // RUNPATH subset of LD_LIBRARY_PATH  -> skip handling Deps
+        if (std::all_of(
+                RPath.begin(), RPath.end(),
+                [&](StringRef item) {
+                  return std::any_of(
+                      searchPaths.begin(), searchPaths.end(),
+                      [&](const AutoLoadDynamicLibraryLookup::SearchPathInfo
+                              &info) { return item == info.Path; });
+                }) &&
+            std::all_of(RunPath.begin(), RunPath.end(), [&](StringRef item) {
+              return std::any_of(
+                  searchPaths.begin(), searchPaths.end(),
+                  [&](const AutoLoadDynamicLibraryLookup::SearchPathInfo
+                          &info) { return item == info.Path; });
+            })) {
+          LLVM_DEBUG(dbgs()
+                     << "Dyld::ScanForLibraries: Skip all deps by Heuristic2: "
+                     << FileName.str() << "\n");
+          return;
+        }
+
+        // Recursively handle dependencies
+        for (StringRef dep : Deps) {
+          std::string dep_full = AutoLoadDylibMgr.lookupLibrary(
+              dep, RPath, RunPath, FileName, false);
+          ProcessLibraryFile(dep_full, level + 1);
+        }
+      };
+
+  for (const AutoLoadDynamicLibraryLookup::SearchPathInfo &Info : searchPaths) {
+    if (Info.IsUser != searchSystemLibraries) {
+      // Examples which we should handle.
+      // File                      Real
+      // /lib/1/1.so               /lib/1/1.so  // file
+      // /lib/1/2.so->/lib/1/1.so  /lib/1/1.so  // file local link
+      // /lib/1/3.so->/lib/3/1.so  /lib/3/1.so  // file external link
+      // /lib/2->/lib/1                         // path link
+      // /lib/2/1.so               /lib/1/1.so  // path link, file
+      // /lib/2/2.so->/lib/1/1.so  /lib/1/1.so  // path link, file local link
+      // /lib/2/3.so->/lib/3/1.so  /lib/3/1.so  // path link, file external link
+      //
+      // /lib/3/1.so
+      // /lib/3/2.so->/system/lib/s.so
+      // /lib/3/3.so
+      // /system/lib/1.so
+      //
+      // libL.so NEEDED/RPATH libR.so    /lib/some-rpath/libR.so  //
+      // needed/dependedt library in libL.so RPATH/RUNPATH or other (in)direct
+      // dep
+      //
+      // Paths = /lib/1 : /lib/2 : /lib/3
+
+      // BasePaths = ["/lib/1", "/lib/3", "/system/lib"]
+      // *Libraries  = [<0,"1.so">, <1,"1.so">, <2,"s.so">, <1,"3.so">]
+
+      LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries Iter:" << Info.Path
+                        << " -> ");
+      std::string RealPath = cached_realpath(Info.Path);
+
+      StringRef DirPath(RealPath);
+      LLVM_DEBUG(dbgs() << RealPath << "\n");
+
+      if (!sys::fs::is_directory(DirPath) || DirPath.empty())
+        continue;
+
+      // Already searched?
+      const BasePath &ScannedBPath = BasePaths.RegisterBasePath(RealPath);
+      if (ScannedPaths.count(&ScannedBPath)) {
+        LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries Already scanned: "
+                          << RealPath << "\n");
+        continue;
+      }
+
+      LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Iterator: " << DirPath
+                        << "\n");
+      std::error_code EC;
+      for (sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd;
+           DirIt != DirEnd && !EC; DirIt.increment(EC)) {
+
+        LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Iterator >>> "
+                          << DirIt->path()
+                          << ", type=" << (short)(DirIt->type()) << "\n");
+
+        const sys::fs::file_type ft = DirIt->type();
+        if (ft == sys::fs::file_type::regular_file) {
+          ProcessLibraryFile(DirIt->path(), 0);
+        } else if (ft == sys::fs::file_type::symlink_file) {
+          std::string DepFileName_str = cached_realpath(DirIt->path());
+          StringRef DepFileName = DepFileName_str;
+          assert(!sys::fs::is_symlink_file(DepFileName));
+          if (!sys::fs::is_directory(DepFileName))
+            ProcessLibraryFile(DepFileName, 0);
+        }
+      }
+      for (sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd;
+           DirIt != DirEnd && !EC; DirIt.increment(EC)) {
+        LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: File " << DirIt->path()
+                          << ", type=" << (short)DirIt->type() << "\n");
+
+        const sys::fs::file_type ft = DirIt->type();
+        if (ft == sys::fs::file_type::regular_file ||
+            (ft == sys::fs::file_type::symlink_file &&
+             !sys::fs::is_symlink_file(DirIt->path()))) {
+          ProcessLibraryFile(DirIt->path(), 0);
+        }
+      }
+
+      // Register the DirPath as fully scanned.
+      ScannedPaths.insert(&ScannedBPath);
+    }
+  }
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::BuildBloomFilter(LibraryPath *Lib,
+                                     object::ObjectFile *BinObjFile,
+                                     unsigned IgnoreSymbolFlags /*= 0*/) const {
+#define DEBUG_TYPE "Dyld::BuildBloomFilter:"
+  assert(UseBloomFilter && "Bloom filter is disabled");
+  assert(!Lib->hasBloomFilter() && "Bloom filter already built!");
+
+  using namespace llvm;
+  // using namespace object;
+
+  LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Building Bloom filter for: "
+                    << Lib->GetFullName() << "\n");
+
+  std::vector<StringRef> symbols;
+  uint32_t SymbolsCount = 0;
+  // Helper to process each symbol from a range
+  auto ProcessSymbols = [&](auto range) {
+    for (const object::SymbolRef &S : range) {
+      uint32_t Flags = cantFail(S.getFlags());
+
+      // Skip symbols based on the flags (e.g., undefined or ignored)
+      if (Flags & IgnoreSymbolFlags || Flags & object::SymbolRef::SF_Undefined)
+        continue;
+
+      Expected<StringRef> SymName = S.getName();
+      if (!SymName || SymName->empty()) {
+        LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Skipped empty or failed "
+                             "to read symbol\n");
+        continue;
+      }
+
+      symbols.push_back(*SymName);
+      ++SymbolsCount;
+    }
+  };
+
+  ProcessSymbols(BinObjFile->symbols());
+
+  if (BinObjFile->isELF()) {
+    // ELF file format has .dynstr section for the dynamic symbol table.
+    const auto *ElfObj = cast<object::ELFObjectFileBase>(BinObjFile);
+    ProcessSymbols(ElfObj->getDynamicSymbolIterators());
+  } else if (BinObjFile->isCOFF()) { // On Windows, the symbols are present in
+                                     // COFF format.
+    object::COFFObjectFile *CoffObj = cast<object::COFFObjectFile>(BinObjFile);
+    // In COFF, the symbols are not present in the SymbolTable section
+    // of the Object file. They are present in the ExportDirectory section.
+    for (const object::ExportDirectoryEntryRef &D :
+         CoffObj->export_directories()) {
+      // All the symbols are already flagged as exported.
+      // We cannot really ignore symbols based on flags as we do on unix.
+      StringRef Name;
+      auto Err = D.getSymbolName(Name);
+
+      if (Err) {
+        std::string Message;
+        handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+          Message += EIB.message() + "; ";
+        });
+        LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Failed to read symbol "
+                          << Message << "\n");
+        continue;
+      }
+      if (Name.empty())
+        continue;
+
+      ++SymbolsCount;
+      symbols.push_back(Name);
+    }
+  }
+
+  // Initialize the Bloom filter with the count of symbols
+  Lib->InitializeBloomFilter(SymbolsCount);
+
+  if (!SymbolsCount) {
+    LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: No symbols found.\n");
+    return;
+  }
+
+  LLVM_DEBUG({
+    dbgs() << "Dyld::BuildBloomFilter: Adding symbols to Bloom filter:\n";
+    for (const auto &Sym : symbols)
+      dbgs() << "- " << Sym << "\n";
+  });
+
+  // Add symbols to the Bloom filter
+  for (const auto &S : symbols) {
+    Lib->AddBloom(UseHashTable ? Lib->AddSymbol(S.str()) : S);
+  }
+#undef DEBUG_TYPE
+}
+
+bool DynamicLoader::ContainsSymbol(const LibraryPath *Lib,
+                                   StringRef mangledName,
+                                   unsigned IgnoreSymbolFlags /*= 0*/) const {
+#define DEBUG_TYPE "Dyld::ContainsSymbol:"
+  // Helper lambda to handle symbol search and logging
+  auto logAndReturn = [](bool result, const std::string &msg) {
+    LLVM_DEBUG(dbgs() << msg);
+    return result;
+  };
+
+  const std::string library_filename = Lib->GetFullName();
+
+  LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Find symbol: lib="
+                    << library_filename << ", mangled=" << mangledName.str()
+                    << "\n");
+
+  auto ObjF = object::ObjectFile::createObjectFile(library_filename);
+  if (Error Err = ObjF.takeError()) {
+    std::string Message;
+    handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+      Message += EIB.message() + "; ";
+    });
+    return logAndReturn(false,
+                        "Dyld::ContainsSymbol: Failed to read object file " +
+                            library_filename + " Errors: " + Message + "\n");
+  }
+
+  object::ObjectFile *BinObjFile = ObjF.get().getBinary();
+  uint32_t hashedMangle = GNUHash(mangledName);
+
+  // Check for the gnu.hash section if ELF and exit early if symbol doesn't
+  // exist
+  if (BinObjFile->isELF() &&
+      !MayExistInElfObjectFile(BinObjFile, hashedMangle)) {
+    return logAndReturn(false,
+                        "Dyld::ContainsSymbol: ELF BloomFilter: Skip symbol <" +
+                            mangledName.str() + ">.\n");
+  }
+
+  // Use Bloom filter if enabled
+  if (UseBloomFilter) {
+    // Use our bloom filters and create them if necessary.
+    if (!Lib->hasBloomFilter()) {
+      BuildBloomFilter(const_cast<LibraryPath *>(Lib), BinObjFile,
+                       IgnoreSymbolFlags);
+    }
+
+    // If the symbol does not exist, exit early. In case it may exist, iterate.
+    if (!Lib->MayExistSymbol(mangledName)) {
+      return logAndReturn(false,
+                          "Dyld::ContainsSymbol: BloomFilter: Skip symbol <" +
+                              mangledName.str() + ">.\n");
+    }
+    LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: BloomFilter: Symbol <"
+                      << mangledName.str() << "> May exist. Search for it.\n");
+  }
+
+  // Use hash table if enabled
+  if (UseHashTable) {
+    bool result = Lib->ExistSymbol(mangledName);
+    return logAndReturn(
+        result, result ? "Dyld::ContainsSymbol: HashTable: Symbol Exist\n"
+                       : "Dyld::ContainsSymbol: HashTable: Symbol Not exis\n");
+  }
+
+  // Symbol not found in hash table; iterate through all symbols
+  LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Iterate all for <"
+                    << mangledName.str() << ">");
+
+  auto ForeachSymbol =
+      [&library_filename](iterator_range<object::symbol_iterator> range,
+                          unsigned IgnoreSymbolFlags,
+                          StringRef mangledName) -> bool {
+    for (const object::SymbolRef &S : range) {
+
+      uint32_t Flags = cantFail(S.getFlags());
+      if (Flags & IgnoreSymbolFlags)
+        continue;
+
+      // Note, we are at last resort and loading library based on a weak
+      // symbol is allowed. Otherwise, the JIT will issue an unresolved
+      // symbol error.
+      //
+      // There are other weak symbol kinds (marked as 'V') to denote
+      // typeinfo and vtables. It is unclear whether we should load such
+      // libraries or from which library we should resolve the symbol.
+      // We seem to not have a way to differentiate it from the symbol API.
+
+      Expected<StringRef> SymNameErr = S.getName();
+      if (!SymNameErr || SymNameErr.get().empty())
+        continue;
+
+      if (SymNameErr.get() == mangledName) {
+        return true;
+      }
+    }
+    return false;
+  };
+
+  // If no hash symbol then iterate to detect symbol
+  // We Iterate only if BloomFilter and/or SymbolHashTable are not supported.
+
+  // Symbol may exist. Iterate.
+  if (ForeachSymbol(BinObjFile->symbols(), IgnoreSymbolFlags, mangledName)) {
+    return logAndReturn(true, "Dyld::ContainsSymbol: Symbol " +
+                                  mangledName.str() + " found in " +
+                                  library_filename + "\n");
+  }
+
+  // Check dynamic symbols for ELF files
+  if (BinObjFile->isELF()) {
+    // ELF file format has .dynstr section for the dynamic symbol table.
+    const auto *ElfObj = cast<object::ELFObjectFileBase>(BinObjFile);
+    bool result = ForeachSymbol(ElfObj->getDynamicSymbolIterators(),
+                                IgnoreSymbolFlags, mangledName);
+    return logAndReturn(
+        result,
+        result ? "Dyld::ContainsSymbol: Symbol found in ELF dynamic symbols.\n"
+               : "Dyld::ContainsSymbol: Symbol not found in ELF dynamic "
+                 "symbols.\n");
+  }
+
+  return logAndReturn(false, "Dyld::ContainsSymbol: Symbol not found.\n");
+#undef DEBUG_TYPE
+}
+
+bool DynamicLoader::ShouldPermanentlyIgnore(StringRef FileName) const {
+#define DEBUG_TYPE "Dyld:"
+  assert(!ExecutableFormat.empty() && "Failed to find the object format!");
+
+  if (!AutoLoadDynamicLibraryLookup::isSharedLibrary(FileName))
+    return true;
+
+  // No need to check linked libraries, as this function is only invoked
+  // for symbols that cannot be found (neither by dlsym nor in the JIT).
+  if (AutoLoadDylibMgr.isLibraryLoaded(FileName))
+    return true;
+
+  auto ObjF = object::ObjectFile::createObjectFile(FileName);
+  if (!ObjF) {
+    LLVM_DEBUG(dbgs() << "[DyLD] Failed to read object file " << FileName
+                      << "\n");
+    return true;
+  }
+
+  object::ObjectFile *file = ObjF.get().getBinary();
+
+  LLVM_DEBUG(dbgs() << "Current executable format: " << ExecutableFormat
+                    << ". Executable format of " << FileName << " : "
+                    << file->getFileFormatName() << "\n");
+
+  // Ignore libraries with different format than the executing one.
+  if (ExecutableFormat != file->getFileFormatName())
+    return true;
+
+  if (isa<object::ELFObjectFileBase>(*file)) {
+    for (auto S : file->sections()) {
+      StringRef name = cantFail(S.getName());
+      if (name == ".text") {
+        // Check if the library has only debug symbols, usually when
+        // stripped with objcopy --only-keep-debug. This check is done by
+        // reading the manual of objcopy and inspection of stripped with
+        // objcopy libraries.
+        auto SecRef = static_cast<object::ELFSectionRef &>(S);
+        if (SecRef.getType() == ELF::SHT_NOBITS)
+          return true;
+
+        return (SecRef.getFlags() & ELF::SHF_ALLOC) == 0;
+      }
+    }
+    return true;
+  }
+
+  // FIXME: Handle osx using isStripped after upgrading to llvm9.
+
+  return ShouldPermanentlyIgnoreCallback(FileName);
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::dumpDebugInfo() const {
+#define DEBUG_TYPE "Dyld:"
+  LLVM_DEBUG({
+    dbgs() << "---\n";
+    size_t x = 0;
+    for (auto const &item : BasePaths.Paths) {
+      dbgs() << "Dyld: - BasePaths[" << x++ << "]:" << &item << ": " << item
+             << "\n";
+    }
+    dbgs() << "---\n";
+    x = 0;
+    for (auto const &item : Libraries.GetLibraries()) {
+      dbgs() << "Dyld: - Libraries[" << x++ << "]:" << &item << ": "
+             << item->Path << ", " << item->LibName << "\n";
+    }
+    x = 0;
+    for (auto const &item : SysLibraries.GetLibraries()) {
+      dbgs() << "Dyld: - SysLibraries[" << x++ << "]:" << &item << ": "
+             << item->Path << ", " << item->LibName << "\n";
+    }
+  });
+#undef DEBUG_TYPE
+}
+
+std::string
+DynamicLoader::searchLibrariesForSymbol(StringRef mangledName,
+                                        bool searchSystem /* = true*/) {
+#define DEBUG_TYPE "Dyld:searchLibrariesForSymbol:"
+  assert(!sys::DynamicLibrary::SearchForAddressOfSymbol(mangledName.str()) &&
+         "Library already loaded, please use dlsym!");
+  assert(!mangledName.empty());
+
+  using namespace sys::path;
+  using namespace sys::fs;
+
+  if (FirstRun) {
+    LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str()
+                      << ", searchSystem=" << (searchSystem ? "true" : "false")
+                      << ", FirstRun(user)... scanning\n");
+
+    LLVM_DEBUG(
+        dbgs()
+        << "Dyld::searchLibrariesForSymbol: Before first ScanForLibraries\n");
+    dumpDebugInfo();
+
+    ScanForLibraries(/* SearchSystemLibraries= */ false);
+    FirstRun = false;
+
+    LLVM_DEBUG(
+        dbgs()
+        << "Dyld::searchLibrariesForSymbol: After first ScanForLibraries\n");
+    dumpDebugInfo();
+  }
+
+  if (QueriedLibraries.size() > 0) {
+    // Last call we were asked if a library contains a symbol. Usually, the
+    // caller wants to load this library. Check if was loaded and remove it
+    // from our lists of not-yet-loaded libs.
+
+    LLVM_DEBUG({
+      dbgs() << "Dyld::ResolveSymbol: QueriedLibraries:\n";
+      size_t x = 0;
+      for (auto item : QueriedLibraries.GetLibraries()) {
+        dbgs() << "Dyld::ResolveSymbol - [" << x++ << "]:" << &item << ": "
+               << item->GetFullName() << "\n";
+      }
+    });
+
+    for (const LibraryPath *P : QueriedLibraries.GetLibraries()) {
+      const std::string LibName = P->GetFullName();
+      if (!AutoLoadDylibMgr.isLibraryLoaded(LibName))
+        continue;
+
+      Libraries.UnregisterLib(*P);
+      SysLibraries.UnregisterLib(*P);
+    }
+    // TODO:  QueriedLibraries.clear ?
+  }
+
+  // Iterate over files under this path. We want to get each ".so" files
+  for (const LibraryPath *P : Libraries.GetLibraries()) {
+    if (ContainsSymbol(P, mangledName, /*ignore*/
+                       object::SymbolRef::SF_Undefined)) {
+      if (!QueriedLibraries.HasRegisteredLib(*P))
+        QueriedLibraries.RegisterLib(*P);
+
+      LLVM_DEBUG(
+          dbgs() << "Dyld::ResolveSymbol: Search found match in [user lib]: "
+                 << P->GetFullName() << "!\n");
+
+      return P->GetFullName();
+    }
+  }
+
+  if (!searchSystem)
+    return "";
+
+  LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: SearchSystem!!!\n");
+
+  // Lookup in non-system libraries failed. Expand the search to the system.
+  if (FirstRunSysLib) {
+    LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str()
+                      << ", searchSystem=" << (searchSystem ? "true" : "false")
+                      << ", FirstRun(system)... scanning\n");
+
+    LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: Before first system "
+                         "ScanForLibraries\n");
+    dumpDebugInfo();
+
+    ScanForLibraries(/* SearchSystemLibraries= */ true);
+    FirstRunSysLib = false;
+
+    LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: After first system "
+                         "ScanForLibraries\n");
+    dumpDebugInfo();
+  }
+
+  for (const LibraryPath *P : SysLibraries.GetLibraries()) {
+    if (ContainsSymbol(P, mangledName, /*ignore*/
+                       object::SymbolRef::SF_Undefined |
+                           object::SymbolRef::SF_Weak)) {
+      if (!QueriedLibraries.HasRegisteredLib(*P))
+        QueriedLibraries.RegisterLib(*P);
+
+      LLVM_DEBUG(
+          dbgs() << "Dyld::ResolveSymbol: Search found match in [system lib]: "
+                 << P->GetFullName() << "!\n");
+
+      return P->GetFullName();
+    }
+  }
+
+  LLVM_DEBUG(dbgs() << "Dyld::ResolveSymbol: Search found no match!\n");
+
+  return ""; // Search found no match.
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::BuildGlobalBloomFilter(BloomFilter &Filter) const {
+  assert(!Filter.IsInitialized());
+  uint32_t GloabalBloomSize = 0;
+
+  for (auto *L : Libraries.GetLibraries()) {
+    GloabalBloomSize += L->Filter.getSymCount();
+  }
+
+  for (auto *L : SysLibraries.GetLibraries()) {
+    GloabalBloomSize += L->Filter.getSymCount();
+  }
+
+  Filter.Initialize(GloabalBloomSize);
+  for (auto *L : Libraries.GetLibraries()) {
+    for (auto &S : L->Symbols) {
+      Filter.AddSymbol(S.getKey());
+    }
+  }
+
+  for (auto *L : SysLibraries.GetLibraries()) {
+    for (auto &S : L->Symbols) {
+      Filter.AddSymbol(S.getKey());
+    }
+  }
+}
+
+AutoLoadDynamicLibraryLookup::~AutoLoadDynamicLibraryLookup() {
+  static_assert(sizeof(Dyld) > 0, "Incomplete type");
+  delete Dyld;
+}
+
+void AutoLoadDynamicLibraryLookup::initializeDynamicLoader(
+    std::function<bool(StringRef)> shouldPermanentlyIgnore) {
+  assert(!Dyld && "Already initialized!");
+  if (Dyld)
+    return;
+  std::string exeP = GetExecutablePath();
+  auto ObjF = cantFail(object::ObjectFile::createObjectFile(exeP));
+
+  Dyld = new DynamicLoader(*this, shouldPermanentlyIgnore,
+                           ObjF.getBinary()->getFileFormatName());
+}
+
+void AutoLoadDynamicLibraryLookup::BuildGlobalBloomFilter(
+    BloomFilter &Filter) const {
+  Dyld->BuildGlobalBloomFilter(Filter);
+}
+
+std::string AutoLoadDynamicLibraryLookup::searchLibrariesForSymbol(
+    StringRef mangledName, bool searchSystem /* = true*/) const {
+  assert(Dyld && "Must call initialize dyld before!");
+  return Dyld->searchLibrariesForSymbol(mangledName, searchSystem);
+}
+
+std::string AutoLoadDynamicLibraryLookup::getSymbolLocation(void *func) {
+#if defined(__CYGWIN__) && defined(__GNUC__)
+  return {};
+#elif defined(_WIN32)
+  MEMORY_BASIC_INFORMATION mbi;
+  if (!VirtualQuery(func, &mbi, sizeof(mbi)))
+    return {};
+
+  HMODULE hMod = (HMODULE)mbi.AllocationBase;
+  char moduleName[MAX_PATH];
+
+  if (!GetModuleFileNameA(hMod, moduleName, sizeof(moduleName)))
+    return {};
+
+  return cached_realpath(moduleName);
+
+#else
+  // assume we have  defined HAVE_DLFCN_H and HAVE_DLADDR
+  Dl_info info;
+  if (dladdr((void *)func, &info) == 0) {
+    // Not in a known shared library, let's give up
+    return {};
+  } else {
+    std::string result = cached_realpath(info.dli_fname);
+    if (!result.empty())
+      return result;
+
+      // Else absolute path. For all we know that's a binary.
+      // Some people have dictionaries in binaries, this is how we find their
+      // path: (see also https://stackoverflow.com/a/1024937/6182509)
+#if defined(__APPLE__)
+    char buf[PATH_MAX] = {0};
+    uint32_t bufsize = sizeof(buf);
+    if (_NSGetExecutablePath(buf, &bufsize) >= 0)
+      return cached_realpath(buf);
+    return cached_realpath(info.dli_fname);
+#elif defined(LLVM_ON_UNIX)
+    char buf[PATH_MAX] = {0};
+    // Cross our fingers that /proc/self/exe exists.
+    if (readlink("/proc/self/exe", buf, sizeof(buf)) > 0)
+      return cached_realpath(buf);
+    std::string pipeCmd = std::string("which \"") + info.dli_fname + "\"";
+    FILE *pipe = popen(pipeCmd.c_str(), "r");
+    if (!pipe)
+      return cached_realpath(info.dli_fname);
+    while (fgets(buf, sizeof(buf), pipe))
+      result += buf;
+
+    pclose(pipe);
+    return cached_realpath(result);
+#else
+#error "Unsupported platform."
+#endif
+    return {};
+  }
+#endif
+}
+
+} // namespace orc
+} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
new file mode 100644
index 00000000000000..b474870cd28cca
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
@@ -0,0 +1,575 @@
+//===---------------- AutoLoadDylibLookup.cpp ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#if defined(_WIN32)
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Support/Endian.h"
+#endif
+
+#include <fstream>
+#include <sys/stat.h>
+#include <system_error>
+
+static bool GetSystemLibraryPaths(llvm::SmallVectorImpl<std::string> &Paths) {
+#if defined(__APPLE__) || defined(__CYGWIN__)
+  Paths.push_back("/usr/local/lib/");
+  Paths.push_back("/usr/X11R6/lib/");
+  Paths.push_back("/usr/lib/");
+  Paths.push_back("/lib/");
+
+#ifndef __APPLE__
+  Paths.push_back("/lib/x86_64-linux-gnu/");
+  Paths.push_back("/usr/local/lib64/");
+  Paths.push_back("/usr/lib64/");
+  Paths.push_back("/lib64/");
+#endif
+#elif defined(LLVM_ON_UNIX)
+  llvm::SmallString<1024> Buf;
+  Popen("LD_DEBUG=libs LD_PRELOAD=DOESNOTEXIST ls", Buf, true);
+  const llvm::StringRef Result = Buf.str();
+
+  const std::size_t NPos = std::string::npos;
+  const std::size_t LD = Result.find("(LD_LIBRARY_PATH)");
+  std::size_t From = Result.find("search path=", LD == NPos ? 0 : LD);
+  if (From != NPos) {
+    std::size_t To = Result.find("(system search path)", From);
+    if (To != NPos) {
+      From += 12;
+      while (To > From && isspace(Result[To - 1]))
+        --To;
+      std::string SysPath = Result.substr(From, To - From).str();
+      SysPath.erase(std::remove_if(SysPath.begin(), SysPath.end(), ::isspace),
+                    SysPath.end());
+
+      llvm::SmallVector<llvm::StringRef, 10> CurPaths;
+      SplitPaths(SysPath, CurPaths);
+      for (const auto &Path : CurPaths)
+        Paths.push_back(Path.str());
+    }
+  }
+#endif
+  return true;
+}
+
+static std::string NormalizePath(const std::string &Path) {
+
+  llvm::SmallString<256> Buffer;
+  std::error_code EC = llvm::sys::fs::real_path(Path, Buffer, true);
+  if (EC)
+    return std::string();
+  return std::string(Buffer.str());
+}
+
+namespace llvm {
+namespace orc {
+
+void LogNonExistantDirectory(StringRef Path) {
+#define DEBUG_TYPE "LogNonExistantDirectory"
+  LLVM_DEBUG(dbgs() << "  ignoring nonexistent directory \"" << Path << "\"\n");
+#undef DEBUG_TYPE
+}
+
+bool SplitPaths(StringRef PathStr, SmallVectorImpl<StringRef> &Paths,
+                SplitMode Mode, StringRef Delim, bool Verbose) {
+#define DEBUG_TYPE "SplitPths"
+
+  assert(Delim.size() && "Splitting without a delimiter");
+
+#if defined(_WIN32)
+  // Support using a ':' delimiter on Windows.
+  const bool WindowsColon = Delim.equals(":");
+#endif
+
+  bool AllExisted = true;
+  for (std::pair<StringRef, StringRef> Split = PathStr.split(Delim);
+       !Split.second.empty(); Split = PathStr.split(Delim)) {
+
+    if (!Split.first.empty()) {
+      bool Exists = sys::fs::is_directory(Split.first);
+
+#if defined(_WIN32)
+      // Because drive letters will have a colon we have to make sure the split
+      // occurs at a colon not followed by a path separator.
+      if (!Exists && WindowsColon && Split.first.size() == 1) {
+        // Both clang and cl.exe support '\' and '/' path separators.
+        if (Split.second.front() == '\\' || Split.second.front() == '/') {
+          const std::pair<StringRef, StringRef> Tmp = Split.second.split(Delim);
+          // Split.first = 'C', but we want 'C:', so Tmp.first.size()+2
+          Split.first = StringRef(Split.first.data(), Tmp.first.size() + 2);
+          Split.second = Tmp.second;
+          Exists = sys::fs::is_directory(Split.first);
+        }
+      }
+#endif
+
+      AllExisted = AllExisted && Exists;
+
+      if (!Exists) {
+        if (Mode == SplitMode::FailNonExistant) {
+          if (Verbose) {
+            // Exiting early, but still log all non-existant paths that we have
+            LogNonExistantDirectory(Split.first);
+            while (!Split.second.empty()) {
+              Split = PathStr.split(Delim);
+              if (sys::fs::is_directory(Split.first)) {
+                LLVM_DEBUG(dbgs() << "  ignoring directory that exists \""
+                                  << Split.first << "\"\n");
+              } else
+                LogNonExistantDirectory(Split.first);
+              Split = Split.second.split(Delim);
+            }
+            if (!sys::fs::is_directory(Split.first))
+              LogNonExistantDirectory(Split.first);
+          }
+          return false;
+        } else if (Mode == SplitMode::AllowNonExistant)
+          Paths.push_back(Split.first);
+        else if (Verbose)
+          LogNonExistantDirectory(Split.first);
+      } else
+        Paths.push_back(Split.first);
+    }
+
+    PathStr = Split.second;
+  }
+
+  // Trim trailing sep in case of A:B:C:D:
+  if (!PathStr.empty() && PathStr.ends_with(Delim))
+    PathStr = PathStr.substr(0, PathStr.size() - Delim.size());
+
+  if (!PathStr.empty()) {
+    if (!sys::fs::is_directory(PathStr)) {
+      AllExisted = false;
+      if (Mode == SplitMode::AllowNonExistant)
+        Paths.push_back(PathStr);
+      else if (Verbose)
+        LogNonExistantDirectory(PathStr);
+    } else
+      Paths.push_back(PathStr);
+  }
+
+  return AllExisted;
+
+#undef DEBUG_TYPE
+}
+
+AutoLoadDynamicLibraryLookup ::AutoLoadDynamicLibraryLookup() {
+  const SmallVector<const char *, 10> kSysLibraryEnv = {
+    "LD_LIBRARY_PATH",
+#if __APPLE__
+    "DYLD_LIBRARY_PATH",
+    "DYLD_FALLBACK_LIBRARY_PATH",
+  /*
+  "DYLD_VERSIONED_LIBRARY_PATH",
+  "DYLD_FRAMEWORK_PATH",
+  "DYLD_FALLBACK_FRAMEWORK_PATH",
+  "DYLD_VERSIONED_FRAMEWORK_PATH",
+  */
+#elif defined(_WIN32)
+    "PATH",
+#endif
+  };
+
+  // Behaviour is to not add paths that don't exist...In an interpreted env
+  // does this make sense? Path could pop into existance at any time.
+  for (const char *Var : kSysLibraryEnv) {
+    if (const char *Env = ::getenv(Var)) {
+      SmallVector<StringRef, 10> CurPaths;
+      SplitPaths(Env, CurPaths, SplitMode::PruneNonExistant, kEnvDelim);
+      for (const auto &Path : CurPaths)
+        addSearchPath(Path);
+    }
+  }
+
+  // $CWD is the last user path searched.
+  addSearchPath(".");
+
+  SmallVector<std::string, 64> SysPaths;
+  GetSystemLibraryPaths(SysPaths);
+
+  for (const std::string &P : SysPaths)
+    addSearchPath(P, /*IsUser*/ false);
+}
+///\returns substitution of pattern in the front of original with replacement
+/// Example: substFront("@rpath/abc", "@rpath/", "/tmp") -> "/tmp/abc"
+static std::string substFront(StringRef original, StringRef pattern,
+                              StringRef replacement) {
+  if (!original.starts_with_insensitive(pattern))
+    return original.str();
+  SmallString<512> result(replacement);
+  result.append(original.drop_front(pattern.size()));
+  return result.str().str();
+}
+
+///\returns substitution of all known linker variables in \c original
+static std::string substAll(StringRef original, StringRef libLoader) {
+
+  // Handle substitutions (MacOS):
+  // @rpath - This function does not substitute @rpath, becouse
+  //          this variable is already handled by lookupLibrary where
+  //          @rpath is replaced with all paths from RPATH one by one.
+  // @executable_path - Main program path.
+  // @loader_path - Loader library (or main program) path.
+  //
+  // Handle substitutions (Linux):
+  // https://man7.org/linux/man-pages/man8/ld.so.8.html
+  // $origin - Loader library (or main program) path.
+  // $lib - lib lib64
+  // $platform - x86_64 AT_PLATFORM
+
+  std::string result;
+#ifdef __APPLE__
+  SmallString<512> mainExecutablePath(
+      llvm::sys::fs::getMainExecutable(nullptr, nullptr));
+  llvm::sys::path::remove_filename(mainExecutablePath);
+  SmallString<512> loaderPath;
+  if (libLoader.empty()) {
+    loaderPath = mainExecutablePath;
+  } else {
+    loaderPath = libLoader.str();
+    llvm::sys::path::remove_filename(loaderPath);
+  }
+
+  result = substFront(original, "@executable_path", mainExecutablePath);
+  result = substFront(result, "@loader_path", loaderPath);
+  return result;
+#else
+  SmallString<512> loaderPath;
+  if (libLoader.empty()) {
+    loaderPath = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+  } else {
+    loaderPath = libLoader.str();
+  }
+  llvm::sys::path::remove_filename(loaderPath);
+
+  result = substFront(original, "$origin", loaderPath);
+  // result = substFront(result, "$lib", true?"lib":"lib64");
+  // result = substFront(result, "$platform", "x86_64");
+  return result;
+#endif
+}
+
+std::string AutoLoadDynamicLibraryLookup::lookupLibInPaths(
+    StringRef libStem, SmallVector<llvm::StringRef, 2> RPath /*={}*/,
+    SmallVector<llvm::StringRef, 2> RunPath /*={}*/,
+    StringRef libLoader /*=""*/) const {
+#define DEBUG_TYPE "Dyld::lookupLibInPaths"
+
+  LLVM_DEBUG(dbgs() << "Dyld::lookupLibInPaths" << libStem.str()
+                    << ", ..., libLoader=" << libLoader << "\n");
+
+  // Lookup priority is: RPATH, LD_LIBRARY_PATH/SearchPaths, RUNPATH
+  // See: https://en.wikipedia.org/wiki/Rpath
+  // See: https://amir.rachum.com/blog/2016/09/17/shared-libraries/
+
+  LLVM_DEBUG({
+    dbgs() << "Dyld::lookupLibInPaths: \n";
+    dbgs() << ":: RPATH\n";
+    for (auto Info : RPath) {
+      dbgs() << ":::: " << Info.str() << "\n";
+    }
+    dbgs() << ":: SearchPaths (LD_LIBRARY_PATH, etc...)\n";
+    for (auto Info : getSearchPaths()) {
+      dbgs() << ":::: " << Info.Path
+             << ", user=" << (Info.IsUser ? "true" : "false") << "\n";
+    }
+    dbgs() << ":: RUNPATH\n";
+    for (auto Info : RunPath) {
+      dbgs() << ":::: " << Info.str() << "\n";
+    }
+  });
+
+  SmallString<512> ThisPath;
+  // RPATH
+  for (auto Info : RPath) {
+    ThisPath = substAll(Info, libLoader);
+    llvm::sys::path::append(ThisPath, libStem);
+    // to absolute path?
+    LLVM_DEBUG(dbgs() << "## Try: " << ThisPath);
+    if (isSharedLibrary(ThisPath.str())) {
+      LLVM_DEBUG(dbgs() << " ... Found (in RPATH)!\n");
+      return ThisPath.str().str();
+    }
+  }
+  // SearchPaths
+  for (const SearchPathInfo &Info : SearchPaths) {
+    ThisPath = Info.Path;
+    llvm::sys::path::append(ThisPath, libStem);
+    // to absolute path?
+    LLVM_DEBUG(dbgs() << "## Try: " << ThisPath);
+    if (isSharedLibrary(ThisPath.str())) {
+      LLVM_DEBUG(dbgs() << " ... Found (in SearchPaths)!\n");
+      return ThisPath.str().str();
+    }
+  }
+  // RUNPATH
+  for (auto Info : RunPath) {
+    ThisPath = substAll(Info, libLoader);
+    llvm::sys::path::append(ThisPath, libStem);
+    // to absolute path?
+    LLVM_DEBUG(dbgs() << "## Try: " << ThisPath);
+    if (isSharedLibrary(ThisPath.str())) {
+      LLVM_DEBUG(dbgs() << " ... Found (in RUNPATH)!\n");
+      return ThisPath.str().str();
+    }
+  }
+
+  LLVM_DEBUG(dbgs() << "## NotFound!!!\n");
+
+  return "";
+
+#undef DEBUG_TYPE
+}
+
+std::string AutoLoadDynamicLibraryLookup::lookupLibMaybeAddExt(
+    StringRef libStem, SmallVector<llvm::StringRef, 2> RPath /*={}*/,
+    SmallVector<llvm::StringRef, 2> RunPath /*={}*/,
+    StringRef libLoader /*=""*/) const {
+#define DEBUG_TYPE "Dyld::lookupLibMaybeAddExt:"
+
+  using namespace llvm::sys;
+
+  LLVM_DEBUG(dbgs() << "Dyld::lookupLibMaybeAddExt: " << libStem.str()
+                    << ", ..., libLoader=" << libLoader << "\n");
+
+  std::string foundDyLib = lookupLibInPaths(libStem, RPath, RunPath, libLoader);
+
+  if (foundDyLib.empty()) {
+    // Add DyLib extension:
+    SmallString<512> filenameWithExt(libStem);
+#if defined(LLVM_ON_UNIX)
+#ifdef __APPLE__
+    SmallString<512>::iterator IStemEnd = filenameWithExt.end() - 1;
+#endif
+    static const char *DyLibExt = ".so";
+#elif defined(_WIN32)
+    static const char *DyLibExt = ".dll";
+#else
+#error "Unsupported platform."
+#endif
+    filenameWithExt += DyLibExt;
+    foundDyLib = lookupLibInPaths(filenameWithExt, RPath, RunPath, libLoader);
+#ifdef __APPLE__
+    if (foundDyLib.empty()) {
+      filenameWithExt.erase(IStemEnd + 1, filenameWithExt.end());
+      filenameWithExt += ".dylib";
+      foundDyLib = lookupLibInPaths(filenameWithExt, RPath, RunPath, libLoader);
+    }
+#endif
+  }
+
+  if (foundDyLib.empty())
+    return std::string();
+
+  // get canonical path name and check if already loaded
+  const std::string Path = NormalizePath(foundDyLib);
+  if (Path.empty()) {
+    LLVM_DEBUG(
+        dbgs() << "AutoLoadDynamicLibraryLookup::lookupLibMaybeAddExt(): "
+               << "error getting real (canonical) path of library "
+               << foundDyLib << '\n');
+    return foundDyLib;
+  }
+  return Path;
+
+#undef DEBUG_TYPE
+}
+
+std::string AutoLoadDynamicLibraryLookup::normalizePath(StringRef path) {
+#define DEBUG_TYPE "Dyld::normalizePath:"
+  // Make the path canonical if the file exists.
+  const std::string Path = path.str();
+  struct stat buffer;
+  if (::stat(Path.c_str(), &buffer) != 0)
+    return std::string();
+
+  const std::string NPath = NormalizePath(Path);
+  if (NPath.empty())
+    LLVM_DEBUG(dbgs() << "Could not normalize: '" << Path << "'");
+  return NPath;
+#undef DEBUG_TYPE
+}
+
+std::string RPathToStr2(SmallVector<StringRef, 2> V) {
+  std::string result;
+  for (auto item : V)
+    result += item.str() + ",";
+  if (!result.empty())
+    result.pop_back();
+  return result;
+}
+
+std::string AutoLoadDynamicLibraryLookup::lookupLibrary(
+    StringRef libStem, SmallVector<llvm::StringRef, 2> RPath /*={}*/,
+    SmallVector<llvm::StringRef, 2> RunPath /*={}*/,
+    StringRef libLoader /*=""*/, bool variateLibStem /*=true*/) const {
+#define DEBUG_TYPE "Dyld::lookupLibrary:"
+  LLVM_DEBUG(dbgs() << "Dyld::lookupLibrary: " << libStem.str() << ", "
+                    << RPathToStr2(RPath) << ", " << RPathToStr2(RunPath)
+                    << ", " << libLoader.str() << "\n");
+  if (libStem.empty())
+    return std::string();
+
+  // If it is an absolute path, don't try iterate over the paths.
+  if (llvm::sys::path::is_absolute(libStem)) {
+    if (isSharedLibrary(libStem))
+      return normalizePath(libStem);
+
+    LLVM_DEBUG(dbgs() << "Dyld::lookupLibrary: '" << libStem.str() << "'"
+                      << "is not a shared library\n");
+    return std::string();
+  }
+
+  // Subst all known linker variables ($origin, @rpath, etc.)
+#ifdef __APPLE__
+  // On MacOS @rpath is preplaced by all paths in RPATH one by one.
+  if (libStem.starts_with_insensitive("@rpath")) {
+    for (auto &P : RPath) {
+      std::string result = substFront(libStem, "@rpath", P);
+      if (isSharedLibrary(result))
+        return normalizePath(result);
+    }
+  } else {
+#endif
+    std::string result = substAll(libStem, libLoader);
+    if (isSharedLibrary(result))
+      return normalizePath(result);
+#ifdef __APPLE__
+  }
+#endif
+
+  // Expand libStem with paths, extensions, etc.
+  std::string foundName;
+  if (variateLibStem) {
+    foundName = lookupLibMaybeAddExt(libStem, RPath, RunPath, libLoader);
+    if (foundName.empty()) {
+      StringRef libStemName = llvm::sys::path::filename(libStem);
+      if (!libStemName.starts_with("lib")) {
+        // try with "lib" prefix:
+        foundName = lookupLibMaybeAddExt(
+            libStem.str().insert(libStem.size() - libStemName.size(), "lib"),
+            RPath, RunPath, libLoader);
+      }
+    }
+  } else {
+    foundName = lookupLibInPaths(libStem, RPath, RunPath, libLoader);
+  }
+
+  if (!foundName.empty())
+    return NormalizePath(foundName);
+
+  return std::string();
+#undef DEBUG_TYPE
+}
+
+void AutoLoadDynamicLibraryLookup::addLoadedLib(StringRef lib) {
+  LoadedLibraries.insert(lib);
+}
+
+bool AutoLoadDynamicLibraryLookup::isLibraryLoaded(StringRef fullPath) const {
+  std::string canonPath = normalizePath(fullPath);
+  if (LoadedLibraries.find(canonPath) != LoadedLibraries.end())
+    return true;
+  return false;
+}
+
+void AutoLoadDynamicLibraryLookup::dump(
+    llvm::raw_ostream *S /*= nullptr*/) const {
+  llvm::raw_ostream &OS = S ? *S : llvm::outs();
+
+  // FIXME: print in a stable order the contents of SearchPaths
+  for (const auto &Info : getSearchPaths()) {
+    if (!Info.IsUser)
+      OS << "[system] ";
+    OS << Info.Path.c_str() << "\n";
+  }
+}
+
+#if defined(_WIN32)
+static bool IsDLL(llvm::StringRef headers) {
+  using namespace llvm::support::endian;
+
+  uint32_t headeroffset = read32le(headers.data() + 0x3c);
+  auto peheader = headers.substr(headeroffset, 24);
+  if (peheader.size() != 24) {
+    return false;
+  }
+  // Read Characteristics from the coff header
+  uint32_t characteristics = read16le(peheader.data() + 22);
+  return (characteristics & llvm::COFF::IMAGE_FILE_DLL) != 0;
+}
+#endif
+
+bool AutoLoadDynamicLibraryLookup::isSharedLibrary(StringRef libFullPath,
+                                                   bool *exists /*=0*/) {
+  using namespace llvm;
+
+  auto filetype = sys::fs::get_file_type(libFullPath, /*Follow*/ true);
+  if (filetype != sys::fs::file_type::regular_file) {
+    if (exists) {
+      // get_file_type returns status_error also in case of file_not_found.
+      *exists = filetype != sys::fs::file_type::status_error;
+    }
+    return false;
+  }
+
+  // Do not use the identify_magic overload taking a path: It will open the
+  // file and then mmap its contents, possibly causing bus errors when another
+  // process truncates the file while we are trying to read it. Instead just
+  // read the first 1024 bytes, which should be enough for identify_magic to
+  // do its work.
+  // TODO: Fix the code upstream and consider going back to calling the
+  // convenience function after a future LLVM upgrade.
+  std::string path = libFullPath.str();
+  std::ifstream in(path, std::ios::binary);
+  char header[1024] = {0};
+  in.read(header, sizeof(header));
+  if (in.fail()) {
+    if (exists)
+      *exists = false;
+    return false;
+  }
+
+  StringRef headerStr(header, in.gcount());
+  file_magic Magic = identify_magic(headerStr);
+
+  bool result =
+#ifdef __APPLE__
+      (Magic == file_magic::macho_fixed_virtual_memory_shared_lib ||
+       Magic == file_magic::macho_dynamically_linked_shared_lib ||
+       Magic == file_magic::macho_dynamically_linked_shared_lib_stub ||
+       Magic == file_magic::macho_universal_binary)
+#elif defined(LLVM_ON_UNIX)
+#ifdef __CYGWIN__
+      (Magic == file_magic::pecoff_executable)
+#else
+      (Magic == file_magic::elf_shared_object)
+#endif
+#elif defined(_WIN32)
+      // We should only include dll libraries without including executables,
+      // object code and others...
+      (Magic == file_magic::pecoff_executable && IsDLL(headerStr))
+#else
+#error "Unsupported platform."
+#endif
+      ;
+
+  return result;
+}
+
+} // end namespace orc
+} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
index 3d1dfe758c79dd..00f142c23356d6 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
@@ -10,6 +10,8 @@ if( LLVM_USE_INTEL_JITEVENTS )
 endif()
 
 add_llvm_component_library(LLVMOrcTargetProcess
+  AutoLoadDylibLookup.cpp
+  AutoLoadDyLoader.cpp
   ExecutorSharedMemoryMapperService.cpp
   JITLoaderGDB.cpp
   JITLoaderPerf.cpp
@@ -30,6 +32,7 @@ add_llvm_component_library(LLVMOrcTargetProcess
 
   LINK_COMPONENTS
   ${intel_jit_profiling}
+  Object
   OrcShared
   Support
   TargetParser
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
index b7e256a826ca43..20f1f45df50d28 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
@@ -11,6 +11,10 @@
 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
 #include "llvm/Support/FormatVariadic.h"
 
+#include <dlfcn.h>
+#include <string>
+#include <unordered_map>
+
 #define DEBUG_TYPE "orc"
 
 namespace llvm {
@@ -65,6 +69,7 @@ SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H,
 #endif
 
       void *Addr = DL.getAddressOfSymbol(DemangledSymName);
+
       if (!Addr && E.Required)
         return make_error<StringError>(Twine("Missing definition for ") +
                                            DemangledSymName,
@@ -78,6 +83,74 @@ SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H,
   return Result;
 }
 
+Expected<ResolveResult>
+SimpleExecutorDylibManager::resolve(const RemoteSymbolLookupSet &L) {
+  if (!DylibLookup.has_value()) {
+    DylibLookup.emplace();
+    DylibLookup->initializeDynamicLoader([](llvm::StringRef) { /*ignore*/
+                                                               return false;
+    });
+  }
+
+  BloomFilter Filter;
+  std::vector<ExecutorSymbolDef> Result;
+  for (auto &E : L) {
+
+    if (E.Name.empty()) {
+      if (E.Required)
+        return make_error<StringError>("Required address for empty symbol \"\"",
+                                       inconvertibleErrorCode());
+      else
+        Result.push_back(ExecutorSymbolDef());
+    } else {
+      const char *DemangledSymName = E.Name.c_str();
+#ifdef __APPLE__
+      if (E.Name.front() != '_')
+        return make_error<StringError>(Twine("MachO symbol \"") + E.Name +
+                                           "\" missing leading '_'",
+                                       inconvertibleErrorCode());
+      ++DemangledSymName;
+#endif
+
+      void *Addr =
+          sys::DynamicLibrary::SearchForAddressOfSymbol(DemangledSymName);
+
+      if (Addr) {
+        Result.push_back(
+            {ExecutorAddr::fromPtr(Addr), JITSymbolFlags::Exported});
+        continue;
+      }
+
+      auto lib = DylibLookup->searchLibrariesForSymbol(E.Name);
+      auto canonicalLoadedLib = DylibLookup->lookupLibrary(lib);
+      if (canonicalLoadedLib.empty()) {
+        if (!Filter.IsInitialized())
+          DylibLookup->BuildGlobalBloomFilter(Filter);
+        Result.push_back(ExecutorSymbolDef());
+      } else {
+        auto H = open(canonicalLoadedLib, 0);
+        if (!H)
+          return H.takeError();
+
+        DylibLookup->addLoadedLib(canonicalLoadedLib);
+        void *Addr = dlsym(H.get().toPtr<void *>(), DemangledSymName);
+        if (!Addr)
+          return make_error<StringError>(Twine("Missing definition for ") +
+                                             DemangledSymName,
+                                         inconvertibleErrorCode());
+        Result.push_back(
+            {ExecutorAddr::fromPtr(Addr), JITSymbolFlags::Exported});
+      }
+    }
+  }
+
+  ResolveResult Res;
+  if (Filter.IsInitialized())
+    Res.Filter.emplace(std::move(Filter));
+  Res.SymbolDef = std::move(Result);
+  return Res;
+}
+
 Error SimpleExecutorDylibManager::shutdown() {
 
   DylibSet DS;
@@ -97,6 +170,8 @@ void SimpleExecutorDylibManager::addBootstrapSymbols(
       ExecutorAddr::fromPtr(&openWrapper);
   M[rt::SimpleExecutorDylibManagerLookupWrapperName] =
       ExecutorAddr::fromPtr(&lookupWrapper);
+  M[rt::SimpleExecutorDylibManagerResolveWrapperName] =
+      ExecutorAddr::fromPtr(&resolveWrapper);
 }
 
 llvm::orc::shared::CWrapperFunctionResult
@@ -119,6 +194,17 @@ SimpleExecutorDylibManager::lookupWrapper(const char *ArgData, size_t ArgSize) {
           .release();
 }
 
+llvm::orc::shared::CWrapperFunctionResult
+SimpleExecutorDylibManager::resolveWrapper(const char *ArgData,
+                                           size_t ArgSize) {
+  return shared::WrapperFunction<
+             rt::SPSSimpleExecutorDylibManagerResolveSignature>::
+      handle(ArgData, ArgSize,
+             shared::makeMethodWrapperHandler(
+                 &SimpleExecutorDylibManager::resolve))
+          .release();
+}
+
 } // namespace rt_bootstrap
 } // end namespace orc
 } // end namespace llvm

>From 74e6356acadc3de50c6d7e18b6023c3eee9e3a23 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 20 Sep 2024 14:20:01 +0530
Subject: [PATCH 2/4] Minor Fix

---
 .../llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h     | 8 ++++----
 .../Orc/TargetProcess/SimpleExecutorDylibManager.cpp      | 1 -
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
index 6bb1b40b1db933..0147aa538fbf7a 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
@@ -82,13 +82,13 @@ class EPCGenericDylibManager {
   void lookupAsync(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &Lookup,
                    SymbolLookupCompleteFn Complete);
 
-  /// Looks up symbols within the given dylib.
+  /// Look up and resolve symbols across all available dynamic libraries.
   void resolveAsync(const SymbolLookupSet &Lookup,
-                           ResolveSymbolsCompleteFn Complete);
+                    ResolveSymbolsCompleteFn Complete);
 
-  /// Looks up symbols within the given dylib.
+  /// Look up and resolve symbols across all available dynamic libraries.
   void resolveAsync(const RemoteSymbolLookupSet &Lookup,
-                           ResolveSymbolsCompleteFn Complete);
+                    ResolveSymbolsCompleteFn Complete);
 
 private:
   ExecutorProcessControl &EPC;
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
index 20f1f45df50d28..92a5a2abd59899 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
@@ -69,7 +69,6 @@ SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H,
 #endif
 
       void *Addr = DL.getAddressOfSymbol(DemangledSymName);
-
       if (!Addr && E.Required)
         return make_error<StringError>(Twine("Missing definition for ") +
                                            DemangledSymName,

>From 6dc3c95ee4021c144e044f094eaca7b694719691 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 30 Sep 2024 15:49:49 +0530
Subject: [PATCH 3/4] Refactor code

---
 .../llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h  | 3 +--
 .../Orc/TargetProcess/AutoLoadDyLoader.cpp                | 2 +-
 .../Orc/TargetProcess/AutoLoadDylibLookUp.cpp             | 8 ++++----
 .../Orc/TargetProcess/SimpleExecutorDylibManager.cpp      | 2 --
 4 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
index 73e8b53edf8598..d1ea9e45d09215 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
@@ -83,8 +83,7 @@ class BloomFilter {
   BloomFilter(const BloomFilter &other) noexcept
       : Initialized(other.Initialized), SymbolsCount(other.SymbolsCount),
         BloomSize(other.BloomSize), BloomShift(other.BloomShift),
-        BloomTable(other.BloomTable) {
-  }
+        BloomTable(other.BloomTable) {}
   BloomFilter &operator=(const BloomFilter &other) = delete;
 
   BloomFilter(BloomFilter &&other) noexcept
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
index 334507b6d371a9..d79a41022b5b55 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
@@ -491,7 +491,7 @@ class DynamicLoader {
       : AutoLoadDylibMgr(DLM), ShouldPermanentlyIgnoreCallback(shouldIgnore),
         ExecutableFormat(execFormat) {}
 
-  ~DynamicLoader(){};
+  ~DynamicLoader() {};
 
   std::string searchLibrariesForSymbol(StringRef mangledName,
                                        bool searchSystem);
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
index b474870cd28cca..da147002962242 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
@@ -169,10 +169,10 @@ bool SplitPaths(StringRef PathStr, SmallVectorImpl<StringRef> &Paths,
 
 AutoLoadDynamicLibraryLookup ::AutoLoadDynamicLibraryLookup() {
   const SmallVector<const char *, 10> kSysLibraryEnv = {
-    "LD_LIBRARY_PATH",
+      "LD_LIBRARY_PATH",
 #if __APPLE__
-    "DYLD_LIBRARY_PATH",
-    "DYLD_FALLBACK_LIBRARY_PATH",
+      "DYLD_LIBRARY_PATH",
+      "DYLD_FALLBACK_LIBRARY_PATH",
   /*
   "DYLD_VERSIONED_LIBRARY_PATH",
   "DYLD_FRAMEWORK_PATH",
@@ -180,7 +180,7 @@ AutoLoadDynamicLibraryLookup ::AutoLoadDynamicLibraryLookup() {
   "DYLD_VERSIONED_FRAMEWORK_PATH",
   */
 #elif defined(_WIN32)
-    "PATH",
+      "PATH",
 #endif
   };
 
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
index 92a5a2abd59899..4066146f1f04a4 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
@@ -12,8 +12,6 @@
 #include "llvm/Support/FormatVariadic.h"
 
 #include <dlfcn.h>
-#include <string>
-#include <unordered_map>
 
 #define DEBUG_TYPE "orc"
 

>From f7300ec8d1ca708fa045745dfeb2db5300adfae4 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 14 Nov 2024 14:47:37 +0530
Subject: [PATCH 4/4] Merge with main branch

---
 llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h       | 7 +++++++
 .../ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h | 2 +-
 .../llvm/ExecutionEngine/Orc/ExecutorProcessControl.h      | 1 -
 llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h    | 3 +++
 .../Orc/EPCDynamicLibrarySearchGenerator.cpp               | 4 ++--
 llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp           | 4 ++--
 6 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h
index bbcc2e639a1865..38699dfcac202d 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_EXECUTIONENGINE_ORC_DYLIBMANAGER_H
 #define LLVM_EXECUTIONENGINE_ORC_DYLIBMANAGER_H
 
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MSVCErrorWorkarounds.h"
@@ -60,6 +61,9 @@ class DylibManager {
   using SymbolLookupCompleteFn =
       unique_function<void(Expected<std::vector<tpctypes::LookupResult>>)>;
 
+  using ResolveSymbolsCompleteFn =
+      unique_function<void(Expected<std::vector<ResolveResult>>)>;
+
   /// Search for symbols in the target process.
   ///
   /// The result of the lookup is a 2-dimensional array of target addresses
@@ -68,6 +72,9 @@ class DylibManager {
   /// symbol is not found then it be assigned a '0' value.
   virtual void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
                                   SymbolLookupCompleteFn F) = 0;
+
+  virtual void resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+                                   ResolveSymbolsCompleteFn F) = 0;
 };
 
 } // end namespace llvm::orc
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
index 901e5d05bbeb18..cfb9353e7b12d1 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
@@ -104,7 +104,7 @@ class AutoLoadDynamicLibrarySearchGenerator : public DefinitionGenerator {
 
   Error
   tryToResolve(SymbolNameSet CandidateSyms,
-               ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn);
+               DylibManager::ResolveSymbolsCompleteFn OnCompleteFn);
 
 private:
   ExecutorProcessControl &EPC;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
index b5fd1c7039af3f..6333efa0f00fc2 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
@@ -16,7 +16,6 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
 #include "llvm/ExecutionEngine/Orc/DylibManager.h"
-#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
index 195cf80a1f0fd2..54d84201ff408f 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
@@ -122,6 +122,9 @@ class SimpleRemoteEPC : public ExecutorProcessControl,
   void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
                           SymbolLookupCompleteFn F) override;
 
+  void resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+                           ResolveSymbolsCompleteFn F) override;
+
   using PendingCallWrapperResultsMap =
     DenseMap<uint64_t, IncomingWFRHandler>;
 
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
index e58f1d1ad51c94..8e0c7f30c1a413 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
@@ -172,7 +172,7 @@ Error AutoLoadDynamicLibrarySearchGenerator::tryToGenerate(
 
 Error AutoLoadDynamicLibrarySearchGenerator::tryToResolve(
     SymbolNameSet CandidateSyms,
-    ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn) {
+    DylibManager::ResolveSymbolsCompleteFn OnCompleteFn) {
 
   LLVM_DEBUG({
     dbgs() << "AutoLoadDynamicLibrarySearchGenerator trying to resolve "
@@ -185,7 +185,7 @@ Error AutoLoadDynamicLibrarySearchGenerator::tryToResolve(
     LookupSymbols.add(S, SymbolLookupFlags::WeaklyReferencedSymbol);
   }
 
-  EPC.resolveSymbolsAsync(LookupSymbols, std::move(OnCompleteFn));
+  EPC.getDylibMgr().resolveSymbolsAsync(LookupSymbols, std::move(OnCompleteFn));
 
   return Error::success();
 }
diff --git a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
index a6de6ca7fc33f5..f9809115c5fd2b 100644
--- a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
@@ -61,7 +61,7 @@ static void
 resolveSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
                           ArrayRef<SymbolLookupSet> Request,
                           std::vector<ResolveResult> Result,
-                          SimpleRemoteEPC::ResolveSymbolsCompleteFn Complete) {
+                          DylibManager::ResolveSymbolsCompleteFn Complete) {
   if (Request.empty())
     return Complete(std::move(Result));
 
@@ -93,7 +93,7 @@ void SimpleRemoteEPC::lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
 
 void SimpleRemoteEPC::resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
                                           ResolveSymbolsCompleteFn Complete) {
-  resolveSymbolsAsyncHelper(*DylibMgr, Request, {}, std::move(Complete));
+  resolveSymbolsAsyncHelper(*EPCDylibMgr, Request, {}, std::move(Complete));
 }
 
 Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,



More information about the llvm-commits mailing list