391 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			391 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- RTDyldObjectLinkingLayer.cpp - RuntimeDyld backed ORC ObjectLayer -===//
 | 
						|
//
 | 
						|
// 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/RTDyldObjectLinkingLayer.h"
 | 
						|
#include "llvm/Object/COFF.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
using namespace llvm::orc;
 | 
						|
 | 
						|
class JITDylibSearchOrderResolver : public JITSymbolResolver {
 | 
						|
public:
 | 
						|
  JITDylibSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {}
 | 
						|
 | 
						|
  void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override {
 | 
						|
    auto &ES = MR.getTargetJITDylib().getExecutionSession();
 | 
						|
    SymbolLookupSet InternedSymbols;
 | 
						|
 | 
						|
    // Intern the requested symbols: lookup takes interned strings.
 | 
						|
    for (auto &S : Symbols)
 | 
						|
      InternedSymbols.add(ES.intern(S));
 | 
						|
 | 
						|
    // Build an OnResolve callback to unwrap the interned strings and pass them
 | 
						|
    // to the OnResolved callback.
 | 
						|
    auto OnResolvedWithUnwrap =
 | 
						|
        [OnResolved = std::move(OnResolved)](
 | 
						|
            Expected<SymbolMap> InternedResult) mutable {
 | 
						|
          if (!InternedResult) {
 | 
						|
            OnResolved(InternedResult.takeError());
 | 
						|
            return;
 | 
						|
          }
 | 
						|
 | 
						|
          LookupResult Result;
 | 
						|
          for (auto &KV : *InternedResult)
 | 
						|
            Result[*KV.first] = std::move(KV.second);
 | 
						|
          OnResolved(Result);
 | 
						|
        };
 | 
						|
 | 
						|
    // Register dependencies for all symbols contained in this set.
 | 
						|
    auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
 | 
						|
      MR.addDependenciesForAll(Deps);
 | 
						|
    };
 | 
						|
 | 
						|
    JITDylibSearchOrder LinkOrder;
 | 
						|
    MR.getTargetJITDylib().withLinkOrderDo(
 | 
						|
        [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; });
 | 
						|
    ES.lookup(LookupKind::Static, LinkOrder, InternedSymbols,
 | 
						|
              SymbolState::Resolved, std::move(OnResolvedWithUnwrap),
 | 
						|
              RegisterDependencies);
 | 
						|
  }
 | 
						|
 | 
						|
  Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override {
 | 
						|
    LookupSet Result;
 | 
						|
 | 
						|
    for (auto &KV : MR.getSymbols()) {
 | 
						|
      if (Symbols.count(*KV.first))
 | 
						|
        Result.insert(*KV.first);
 | 
						|
    }
 | 
						|
 | 
						|
    return Result;
 | 
						|
  }
 | 
						|
 | 
						|
private:
 | 
						|
  MaterializationResponsibility &MR;
 | 
						|
};
 | 
						|
 | 
						|
} // end anonymous namespace
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace orc {
 | 
						|
 | 
						|
char RTDyldObjectLinkingLayer::ID;
 | 
						|
 | 
						|
using BaseT = RTTIExtends<RTDyldObjectLinkingLayer, ObjectLayer>;
 | 
						|
 | 
						|
RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer(
 | 
						|
    ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager)
 | 
						|
    : BaseT(ES), GetMemoryManager(GetMemoryManager) {
 | 
						|
  ES.registerResourceManager(*this);
 | 
						|
}
 | 
						|
 | 
						|
RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() {
 | 
						|
  assert(MemMgrs.empty() && "Layer destroyed with resources still attached");
 | 
						|
}
 | 
						|
 | 
						|
void RTDyldObjectLinkingLayer::emit(
 | 
						|
    std::unique_ptr<MaterializationResponsibility> R,
 | 
						|
    std::unique_ptr<MemoryBuffer> O) {
 | 
						|
  assert(O && "Object must not be null");
 | 
						|
 | 
						|
  auto &ES = getExecutionSession();
 | 
						|
 | 
						|
  auto Obj = object::ObjectFile::createObjectFile(*O);
 | 
						|
 | 
						|
  if (!Obj) {
 | 
						|
    getExecutionSession().reportError(Obj.takeError());
 | 
						|
    R->failMaterialization();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Collect the internal symbols from the object file: We will need to
 | 
						|
  // filter these later.
 | 
						|
  auto InternalSymbols = std::make_shared<std::set<StringRef>>();
 | 
						|
  {
 | 
						|
    SymbolFlagsMap ExtraSymbolsToClaim;
 | 
						|
    for (auto &Sym : (*Obj)->symbols()) {
 | 
						|
 | 
						|
      // Skip file symbols.
 | 
						|
      if (auto SymType = Sym.getType()) {
 | 
						|
        if (*SymType == object::SymbolRef::ST_File)
 | 
						|
          continue;
 | 
						|
      } else {
 | 
						|
        ES.reportError(SymType.takeError());
 | 
						|
        R->failMaterialization();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
 | 
						|
      if (!SymFlagsOrErr) {
 | 
						|
        // TODO: Test this error.
 | 
						|
        ES.reportError(SymFlagsOrErr.takeError());
 | 
						|
        R->failMaterialization();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      // Try to claim responsibility of weak symbols
 | 
						|
      // if AutoClaimObjectSymbols flag is set.
 | 
						|
      if (AutoClaimObjectSymbols &&
 | 
						|
          (*SymFlagsOrErr & object::BasicSymbolRef::SF_Weak)) {
 | 
						|
        auto SymName = Sym.getName();
 | 
						|
        if (!SymName) {
 | 
						|
          ES.reportError(SymName.takeError());
 | 
						|
          R->failMaterialization();
 | 
						|
          return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Already included in responsibility set, skip it
 | 
						|
        SymbolStringPtr SymbolName = ES.intern(*SymName);
 | 
						|
        if (R->getSymbols().count(SymbolName))
 | 
						|
          continue;
 | 
						|
 | 
						|
        auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
 | 
						|
        if (!SymFlags) {
 | 
						|
          ES.reportError(SymFlags.takeError());
 | 
						|
          R->failMaterialization();
 | 
						|
          return;
 | 
						|
        }
 | 
						|
 | 
						|
        ExtraSymbolsToClaim[SymbolName] = *SymFlags;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      // Don't include symbols that aren't global.
 | 
						|
      if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) {
 | 
						|
        if (auto SymName = Sym.getName())
 | 
						|
          InternalSymbols->insert(*SymName);
 | 
						|
        else {
 | 
						|
          ES.reportError(SymName.takeError());
 | 
						|
          R->failMaterialization();
 | 
						|
          return;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!ExtraSymbolsToClaim.empty()) {
 | 
						|
      if (auto Err = R->defineMaterializing(ExtraSymbolsToClaim)) {
 | 
						|
        ES.reportError(std::move(Err));
 | 
						|
        R->failMaterialization();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  auto MemMgr = GetMemoryManager();
 | 
						|
  auto &MemMgrRef = *MemMgr;
 | 
						|
 | 
						|
  // Switch to shared ownership of MR so that it can be captured by both
 | 
						|
  // lambdas below.
 | 
						|
  std::shared_ptr<MaterializationResponsibility> SharedR(std::move(R));
 | 
						|
 | 
						|
  JITDylibSearchOrderResolver Resolver(*SharedR);
 | 
						|
 | 
						|
  jitLinkForORC(
 | 
						|
      object::OwningBinary<object::ObjectFile>(std::move(*Obj), std::move(O)),
 | 
						|
      MemMgrRef, Resolver, ProcessAllSections,
 | 
						|
      [this, SharedR, &MemMgrRef, InternalSymbols](
 | 
						|
          const object::ObjectFile &Obj,
 | 
						|
          RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,
 | 
						|
          std::map<StringRef, JITEvaluatedSymbol> ResolvedSymbols) {
 | 
						|
        return onObjLoad(*SharedR, Obj, MemMgrRef, LoadedObjInfo,
 | 
						|
                         ResolvedSymbols, *InternalSymbols);
 | 
						|
      },
 | 
						|
      [this, SharedR, MemMgr = std::move(MemMgr)](
 | 
						|
          object::OwningBinary<object::ObjectFile> Obj,
 | 
						|
          std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,
 | 
						|
          Error Err) mutable {
 | 
						|
        onObjEmit(*SharedR, std::move(Obj), std::move(MemMgr),
 | 
						|
                  std::move(LoadedObjInfo), std::move(Err));
 | 
						|
      });
 | 
						|
}
 | 
						|
 | 
						|
void RTDyldObjectLinkingLayer::registerJITEventListener(JITEventListener &L) {
 | 
						|
  std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
 | 
						|
  assert(!llvm::is_contained(EventListeners, &L) &&
 | 
						|
         "Listener has already been registered");
 | 
						|
  EventListeners.push_back(&L);
 | 
						|
}
 | 
						|
 | 
						|
void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener &L) {
 | 
						|
  std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
 | 
						|
  auto I = llvm::find(EventListeners, &L);
 | 
						|
  assert(I != EventListeners.end() && "Listener not registered");
 | 
						|
  EventListeners.erase(I);
 | 
						|
}
 | 
						|
 | 
						|
Error RTDyldObjectLinkingLayer::onObjLoad(
 | 
						|
    MaterializationResponsibility &R, const object::ObjectFile &Obj,
 | 
						|
    RuntimeDyld::MemoryManager &MemMgr,
 | 
						|
    RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,
 | 
						|
    std::map<StringRef, JITEvaluatedSymbol> Resolved,
 | 
						|
    std::set<StringRef> &InternalSymbols) {
 | 
						|
  SymbolFlagsMap ExtraSymbolsToClaim;
 | 
						|
  SymbolMap Symbols;
 | 
						|
 | 
						|
  // Hack to support COFF constant pool comdats introduced during compilation:
 | 
						|
  // (See http://llvm.org/PR40074)
 | 
						|
  if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(&Obj)) {
 | 
						|
    auto &ES = getExecutionSession();
 | 
						|
 | 
						|
    // For all resolved symbols that are not already in the responsibilty set:
 | 
						|
    // check whether the symbol is in a comdat section and if so mark it as
 | 
						|
    // weak.
 | 
						|
    for (auto &Sym : COFFObj->symbols()) {
 | 
						|
      // getFlags() on COFF symbols can't fail.
 | 
						|
      uint32_t SymFlags = cantFail(Sym.getFlags());
 | 
						|
      if (SymFlags & object::BasicSymbolRef::SF_Undefined)
 | 
						|
        continue;
 | 
						|
      auto Name = Sym.getName();
 | 
						|
      if (!Name)
 | 
						|
        return Name.takeError();
 | 
						|
      auto I = Resolved.find(*Name);
 | 
						|
 | 
						|
      // Skip unresolved symbols, internal symbols, and symbols that are
 | 
						|
      // already in the responsibility set.
 | 
						|
      if (I == Resolved.end() || InternalSymbols.count(*Name) ||
 | 
						|
          R.getSymbols().count(ES.intern(*Name)))
 | 
						|
        continue;
 | 
						|
      auto Sec = Sym.getSection();
 | 
						|
      if (!Sec)
 | 
						|
        return Sec.takeError();
 | 
						|
      if (*Sec == COFFObj->section_end())
 | 
						|
        continue;
 | 
						|
      auto &COFFSec = *COFFObj->getCOFFSection(**Sec);
 | 
						|
      if (COFFSec.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT)
 | 
						|
        I->second.setFlags(I->second.getFlags() | JITSymbolFlags::Weak);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (auto &KV : Resolved) {
 | 
						|
    // Scan the symbols and add them to the Symbols map for resolution.
 | 
						|
 | 
						|
    // We never claim internal symbols.
 | 
						|
    if (InternalSymbols.count(KV.first))
 | 
						|
      continue;
 | 
						|
 | 
						|
    auto InternedName = getExecutionSession().intern(KV.first);
 | 
						|
    auto Flags = KV.second.getFlags();
 | 
						|
 | 
						|
    // Override object flags and claim responsibility for symbols if
 | 
						|
    // requested.
 | 
						|
    if (OverrideObjectFlags || AutoClaimObjectSymbols) {
 | 
						|
      auto I = R.getSymbols().find(InternedName);
 | 
						|
 | 
						|
      if (OverrideObjectFlags && I != R.getSymbols().end())
 | 
						|
        Flags = I->second;
 | 
						|
      else if (AutoClaimObjectSymbols && I == R.getSymbols().end())
 | 
						|
        ExtraSymbolsToClaim[InternedName] = Flags;
 | 
						|
    }
 | 
						|
 | 
						|
    Symbols[InternedName] = JITEvaluatedSymbol(KV.second.getAddress(), Flags);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ExtraSymbolsToClaim.empty()) {
 | 
						|
    if (auto Err = R.defineMaterializing(ExtraSymbolsToClaim))
 | 
						|
      return Err;
 | 
						|
 | 
						|
    // If we claimed responsibility for any weak symbols but were rejected then
 | 
						|
    // we need to remove them from the resolved set.
 | 
						|
    for (auto &KV : ExtraSymbolsToClaim)
 | 
						|
      if (KV.second.isWeak() && !R.getSymbols().count(KV.first))
 | 
						|
        Symbols.erase(KV.first);
 | 
						|
  }
 | 
						|
 | 
						|
  if (auto Err = R.notifyResolved(Symbols)) {
 | 
						|
    R.failMaterialization();
 | 
						|
    return Err;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NotifyLoaded)
 | 
						|
    NotifyLoaded(R, Obj, LoadedObjInfo);
 | 
						|
 | 
						|
  return Error::success();
 | 
						|
}
 | 
						|
 | 
						|
void RTDyldObjectLinkingLayer::onObjEmit(
 | 
						|
    MaterializationResponsibility &R,
 | 
						|
    object::OwningBinary<object::ObjectFile> O,
 | 
						|
    std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr,
 | 
						|
    std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo, Error Err) {
 | 
						|
  if (Err) {
 | 
						|
    getExecutionSession().reportError(std::move(Err));
 | 
						|
    R.failMaterialization();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (auto Err = R.notifyEmitted()) {
 | 
						|
    getExecutionSession().reportError(std::move(Err));
 | 
						|
    R.failMaterialization();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  std::unique_ptr<object::ObjectFile> Obj;
 | 
						|
  std::unique_ptr<MemoryBuffer> ObjBuffer;
 | 
						|
  std::tie(Obj, ObjBuffer) = O.takeBinary();
 | 
						|
 | 
						|
  // Run EventListener notifyLoaded callbacks.
 | 
						|
  {
 | 
						|
    std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
 | 
						|
    for (auto *L : EventListeners)
 | 
						|
      L->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr.get()), *Obj,
 | 
						|
                            *LoadedObjInfo);
 | 
						|
  }
 | 
						|
 | 
						|
  if (NotifyEmitted)
 | 
						|
    NotifyEmitted(R, std::move(ObjBuffer));
 | 
						|
 | 
						|
  if (auto Err = R.withResourceKeyDo(
 | 
						|
          [&](ResourceKey K) { MemMgrs[K].push_back(std::move(MemMgr)); })) {
 | 
						|
    getExecutionSession().reportError(std::move(Err));
 | 
						|
    R.failMaterialization();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
Error RTDyldObjectLinkingLayer::handleRemoveResources(ResourceKey K) {
 | 
						|
 | 
						|
  std::vector<MemoryManagerUP> MemMgrsToRemove;
 | 
						|
 | 
						|
  getExecutionSession().runSessionLocked([&] {
 | 
						|
    auto I = MemMgrs.find(K);
 | 
						|
    if (I != MemMgrs.end()) {
 | 
						|
      std::swap(MemMgrsToRemove, I->second);
 | 
						|
      MemMgrs.erase(I);
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  {
 | 
						|
    std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
 | 
						|
    for (auto &MemMgr : MemMgrsToRemove) {
 | 
						|
      for (auto *L : EventListeners)
 | 
						|
        L->notifyFreeingObject(pointerToJITTargetAddress(MemMgr.get()));
 | 
						|
      MemMgr->deregisterEHFrames();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Error::success();
 | 
						|
}
 | 
						|
 | 
						|
void RTDyldObjectLinkingLayer::handleTransferResources(ResourceKey DstKey,
 | 
						|
                                                       ResourceKey SrcKey) {
 | 
						|
  auto I = MemMgrs.find(SrcKey);
 | 
						|
  if (I != MemMgrs.end()) {
 | 
						|
    auto &SrcMemMgrs = I->second;
 | 
						|
    auto &DstMemMgrs = MemMgrs[DstKey];
 | 
						|
    DstMemMgrs.reserve(DstMemMgrs.size() + SrcMemMgrs.size());
 | 
						|
    for (auto &MemMgr : SrcMemMgrs)
 | 
						|
      DstMemMgrs.push_back(std::move(MemMgr));
 | 
						|
 | 
						|
    // Erase SrcKey entry using value rather than iterator I: I may have been
 | 
						|
    // invalidated when we looked up DstKey.
 | 
						|
    MemMgrs.erase(SrcKey);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
} // End namespace orc.
 | 
						|
} // End namespace llvm.
 |