[ORC][COFF] Introduce DLLImportDefinitionGenerator.
authorSunho Kim <ksunhokim123@gmail.com>
Mon, 15 Aug 2022 16:35:18 +0000 (01:35 +0900)
committerSunho Kim <ksunhokim123@gmail.com>
Mon, 15 Aug 2022 17:06:57 +0000 (02:06 +0900)
This class will be used to properly solve the `__imp_` symbol and jump-thunk generation issues. It is assumed to be the last definition generator to be called, and as it's the last generator the only symbols remaining in the lookup set are the symbols that are supposed to be queried outside this jitdylib. Instead of just letting them through, we issue another lookup invocation and fetch the allocated addresses, and then create jitlink graph containing `__imp_` GOT symbols and jump-thunks targetting the fetched addresses.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D131833

llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp

index b60c086..812313b 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/ExecutionEngine/Orc/Mangling.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
 #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
 #include "llvm/ExecutionEngine/RuntimeDyld.h"
 #include "llvm/Object/Archive.h"
@@ -314,6 +315,40 @@ private:
   DenseMap<SymbolStringPtr, MemoryBufferRef> ObjectFilesMap;
 };
 
+/// A utility class to create COFF dllimport GOT symbols (__imp_*) and PLT
+/// stubs.
+///
+/// If an instance of this class is attached to a JITDylib as a fallback
+/// definition generator, PLT stubs and dllimport __imp_ symbols will be
+/// generated for external symbols found outside the given jitdylib. Currently
+/// only supports x86_64 architecture.
+class DLLImportDefinitionGenerator : public DefinitionGenerator {
+public:
+  /// Creates a DLLImportDefinitionGenerator instance.
+  static std::unique_ptr<DLLImportDefinitionGenerator>
+  Create(ExecutionSession &ES, ObjectLinkingLayer &L);
+
+  Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
+                      JITDylibLookupFlags JDLookupFlags,
+                      const SymbolLookupSet &Symbols) override;
+
+private:
+  DLLImportDefinitionGenerator(ExecutionSession &ES, ObjectLinkingLayer &L)
+      : ES(ES), L(L) {}
+
+  static Expected<unsigned> getTargetPointerSize(const Triple &TT);
+  static Expected<support::endianness> getTargetEndianness(const Triple &TT);
+  Expected<std::unique_ptr<jitlink::LinkGraph>>
+  createStubsGraph(const SymbolMap &Resolved);
+
+  static StringRef getImpPrefix() { return "__imp_"; }
+
+  static StringRef getSectionName() { return "$__DLLIMPORT_STUBS"; }
+
+  ExecutionSession &ES;
+  ObjectLinkingLayer &L;
+};
+
 } // end namespace orc
 } // end namespace llvm
 
index 090e90c..da96a59 100644 (file)
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/JITLink/x86_64.h"
 #include "llvm/ExecutionEngine/Orc/Layer.h"
 #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
 #include "llvm/IR/Constants.h"
@@ -350,7 +351,6 @@ StaticLibraryDefinitionGenerator::Create(
 Error StaticLibraryDefinitionGenerator::tryToGenerate(
     LookupState &LS, LookupKind K, JITDylib &JD,
     JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {
-
   // Don't materialize symbols from static archives unless this is a static
   // lookup.
   if (K != LookupKind::Static)
@@ -430,5 +430,121 @@ StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator(
     Err = buildObjectFilesMap();
 }
 
+std::unique_ptr<DLLImportDefinitionGenerator>
+DLLImportDefinitionGenerator::Create(ExecutionSession &ES,
+                                     ObjectLinkingLayer &L) {
+  return std::unique_ptr<DLLImportDefinitionGenerator>(
+      new DLLImportDefinitionGenerator(ES, L));
+}
+
+Error DLLImportDefinitionGenerator::tryToGenerate(
+    LookupState &LS, LookupKind K, JITDylib &JD,
+    JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {
+  JITDylibSearchOrder LinkOrder;
+  JD.withLinkOrderDo([&](const JITDylibSearchOrder &LO) {
+    LinkOrder.reserve(LO.size());
+    for (auto &KV : LO) {
+      if (KV.first == &JD)
+        continue;
+      LinkOrder.push_back(KV);
+    }
+  });
+
+  // FIXME: if regular symbol name start with __imp_ we have to issue lookup of
+  // both __imp_ and stripped name and use the lookup information to resolve the
+  // real symbol name.
+  SymbolLookupSet LookupSet;
+  DenseMap<StringRef, SymbolLookupFlags> ToLookUpSymbols;
+  for (auto &KV : Symbols) {
+    StringRef Deinterned = *KV.first;
+    if (Deinterned.startswith(getImpPrefix()))
+      Deinterned = Deinterned.drop_front(StringRef(getImpPrefix()).size());
+    // Don't degrade the required state
+    if (ToLookUpSymbols.count(Deinterned) &&
+        ToLookUpSymbols[Deinterned] == SymbolLookupFlags::RequiredSymbol)
+      continue;
+    ToLookUpSymbols[Deinterned] = KV.second;
+  }
+
+  for (auto &KV : ToLookUpSymbols)
+    LookupSet.add(ES.intern(KV.first), KV.second);
+
+  auto Resolved =
+      ES.lookup(LinkOrder, LookupSet, LookupKind::DLSym, SymbolState::Resolved);
+  if (!Resolved)
+    return Resolved.takeError();
+
+  auto G = createStubsGraph(*Resolved);
+  if (!G)
+    return G.takeError();
+  return L.add(JD, std::move(*G));
+}
+
+Expected<unsigned>
+DLLImportDefinitionGenerator::getTargetPointerSize(const Triple &TT) {
+  switch (TT.getArch()) {
+  case Triple::x86_64:
+    return 8;
+  default:
+    return make_error<StringError>(
+        "architecture unsupported by DLLImportDefinitionGenerator",
+        inconvertibleErrorCode());
+  }
+}
+
+Expected<support::endianness>
+DLLImportDefinitionGenerator::getTargetEndianness(const Triple &TT) {
+  switch (TT.getArch()) {
+  case Triple::x86_64:
+    return support::endianness::little;
+  default:
+    return make_error<StringError>(
+        "architecture unsupported by DLLImportDefinitionGenerator",
+        inconvertibleErrorCode());
+  }
+}
+
+Expected<std::unique_ptr<jitlink::LinkGraph>>
+DLLImportDefinitionGenerator::createStubsGraph(const SymbolMap &Resolved) {
+  Triple TT = ES.getExecutorProcessControl().getTargetTriple();
+  auto PointerSize = getTargetEndianness(TT);
+  if (!PointerSize)
+    return std::move(PointerSize.takeError());
+  auto Endianness = getTargetEndianness(TT);
+  if (!Endianness)
+    return std::move(Endianness.takeError());
+
+  auto G = std::make_unique<jitlink::LinkGraph>(
+      "<DLLIMPORT_STUBS>", TT, *PointerSize, *Endianness,
+      jitlink::getGenericEdgeKindName);
+  jitlink::Section &Sec = G->createSection(
+      getSectionName(), jitlink::MemProt::Read | jitlink::MemProt::Exec);
+
+  for (auto &KV : Resolved) {
+    jitlink::Symbol &Target = G->addAbsoluteSymbol(
+        *KV.first, ExecutorAddr(KV.second.getAddress()), *PointerSize,
+        jitlink::Linkage::Strong, jitlink::Scope::Local, false);
+
+    // Create __imp_ symbol
+    jitlink::Symbol &Ptr =
+        jitlink::x86_64::createAnonymousPointer(*G, Sec, &Target);
+    auto NameCopy = G->allocateString(Twine(getImpPrefix()) + *KV.first);
+    StringRef NameCopyRef = StringRef(NameCopy.data(), NameCopy.size());
+    Ptr.setName(NameCopyRef);
+    Ptr.setLinkage(jitlink::Linkage::Strong);
+    Ptr.setScope(jitlink::Scope::Default);
+
+    // Create PLT stub
+    // FIXME: check PLT stub of data symbol is not accessed
+    jitlink::Block &StubBlock =
+        jitlink::x86_64::createPointerJumpStubBlock(*G, Sec, Ptr);
+    G->addDefinedSymbol(StubBlock, 0, *KV.first, StubBlock.getSize(),
+                        jitlink::Linkage::Strong, jitlink::Scope::Default, true,
+                        false);
+  }
+
+  return std::move(G);
+}
+
 } // End namespace orc.
 } // End namespace llvm.