[ORC][COFF] Introduce DLLImportDefinitionGenerator.

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
This commit is contained in:
Sunho Kim 2022-08-16 01:35:18 +09:00
parent e5748c6e73
commit 0c69f9f32c
2 changed files with 152 additions and 1 deletions

View File

@ -18,6 +18,7 @@
#include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/Mangling.h" #include "llvm/ExecutionEngine/Orc/Mangling.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/Shared/OrcError.h" #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/Object/Archive.h" #include "llvm/Object/Archive.h"
@ -314,6 +315,40 @@ private:
DenseMap<SymbolStringPtr, MemoryBufferRef> ObjectFilesMap; 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 orc
} // end namespace llvm } // end namespace llvm

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
#include "llvm/ExecutionEngine/Orc/Layer.h" #include "llvm/ExecutionEngine/Orc/Layer.h"
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
@ -350,7 +351,6 @@ StaticLibraryDefinitionGenerator::Create(
Error StaticLibraryDefinitionGenerator::tryToGenerate( Error StaticLibraryDefinitionGenerator::tryToGenerate(
LookupState &LS, LookupKind K, JITDylib &JD, LookupState &LS, LookupKind K, JITDylib &JD,
JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {
// Don't materialize symbols from static archives unless this is a static // Don't materialize symbols from static archives unless this is a static
// lookup. // lookup.
if (K != LookupKind::Static) if (K != LookupKind::Static)
@ -430,5 +430,121 @@ StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator(
Err = buildObjectFilesMap(); 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 orc.
} // End namespace llvm. } // End namespace llvm.