169 changes: 116 additions & 53 deletions llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "llvm/ExecutionEngine/Orc/COFFPlatform.h"
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"

#include "llvm/Object/COFF.h"

Expand Down Expand Up @@ -161,7 +162,7 @@ namespace orc {
Expected<std::unique_ptr<COFFPlatform>>
COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
LoadDynamicLibrary LoadDynLibrary,
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
const char *VCRuntimePath,
Optional<SymbolAliasMap> RuntimeAliases) {
auto &EPC = ES.getExecutorProcessControl();
Expand All @@ -180,8 +181,10 @@ COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
return std::move(Err);

auto &HostFuncJD = ES.createBareJITDylib("$<PlatformRuntimeHostFuncJD>");

// Add JIT-dispatch function support symbols.
if (auto Err = PlatformJD.define(absoluteSymbols(
if (auto Err = HostFuncJD.define(absoluteSymbols(
{{ES.intern("__orc_rt_jit_dispatch"),
{EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
JITSymbolFlags::Exported}},
Expand All @@ -190,22 +193,44 @@ COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITSymbolFlags::Exported}}})))
return std::move(Err);

// Create a generator for the ORC runtime archive.
auto OrcRuntimeArchiveGenerator =
StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
if (!OrcRuntimeArchiveGenerator)
return OrcRuntimeArchiveGenerator.takeError();
PlatformJD.addToLinkOrder(HostFuncJD);

// Create the instance.
Error Err = Error::success();
auto P = std::unique_ptr<COFFPlatform>(new COFFPlatform(
ES, ObjLinkingLayer, PlatformJD, std::move(*OrcRuntimeArchiveGenerator),
std::move(LoadDynLibrary), VCRuntimePath, Err));
ES, ObjLinkingLayer, PlatformJD, OrcRuntimePath,
std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath, Err));
if (Err)
return std::move(Err);
return std::move(P);
}

Expected<MemoryBufferRef> COFFPlatform::getPerJDObjectFile() {
auto PerJDObj = OrcRuntimeArchive->findSym("__orc_rt_coff_per_jd_marker");
if (!PerJDObj)
return PerJDObj.takeError();

if (!*PerJDObj)
return make_error<StringError>("Could not find per jd object file",
inconvertibleErrorCode());

auto Buffer = (*PerJDObj)->getAsBinary();
if (!Buffer)
return Buffer.takeError();

return (*Buffer)->getMemoryBufferRef();
}

static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
ArrayRef<std::pair<const char *, const char *>> AL) {
for (auto &KV : AL) {
auto AliasName = ES.intern(KV.first);
assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
Aliases[std::move(AliasName)] = {ES.intern(KV.second),
JITSymbolFlags::Exported};
}
}

Error COFFPlatform::setupJITDylib(JITDylib &JD) {
if (auto Err = JD.define(std::make_unique<COFFHeaderMaterializationUnit>(
*this, COFFHeaderStartSymbol)))
Expand All @@ -214,17 +239,39 @@ Error COFFPlatform::setupJITDylib(JITDylib &JD) {
if (auto Err = ES.lookup({&JD}, COFFHeaderStartSymbol).takeError())
return Err;

// Define the CXX aliases.
SymbolAliasMap CXXAliases;
addAliases(ES, CXXAliases, requiredCXXAliases());
if (auto Err = JD.define(symbolAliases(std::move(CXXAliases))))
return std::move(Err);

auto PerJDObj = getPerJDObjectFile();
if (!PerJDObj)
return PerJDObj.takeError();

auto I = getObjectFileInterface(ES, *PerJDObj);
if (!I)
return I.takeError();

if (auto Err = ObjLinkingLayer.add(
JD, MemoryBuffer::getMemBuffer(*PerJDObj, false), std::move(*I)))
return Err;

if (!Bootstrapping) {
auto ImportedLibs = VCRuntimeBootstrap->loadStaticVCRuntime(JD);
auto ImportedLibs = StaticVCRuntime
? VCRuntimeBootstrap->loadStaticVCRuntime(JD)
: VCRuntimeBootstrap->loadDynamicVCRuntime(JD);
if (!ImportedLibs)
return ImportedLibs.takeError();
for (auto &Lib : *ImportedLibs)
if (auto Err = LoadDynLibrary(JD, Lib))
return Err;
if (auto Err = VCRuntimeBootstrap->initializeStaticVCRuntime(JD))
return Err;
if (StaticVCRuntime)
if (auto Err = VCRuntimeBootstrap->initializeStaticVCRuntime(JD))
return Err;
}

JD.addGenerator(DLLImportDefinitionGenerator::Create(ES, ObjLinkingLayer));
return Error::success();
}

Expand Down Expand Up @@ -261,19 +308,8 @@ Error COFFPlatform::notifyRemoving(ResourceTracker &RT) {
llvm_unreachable("Not supported yet");
}

static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
ArrayRef<std::pair<const char *, const char *>> AL) {
for (auto &KV : AL) {
auto AliasName = ES.intern(KV.first);
assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
Aliases[std::move(AliasName)] = {ES.intern(KV.second),
JITSymbolFlags::Exported};
}
}

SymbolAliasMap COFFPlatform::standardPlatformAliases(ExecutionSession &ES) {
SymbolAliasMap Aliases;
addAliases(ES, Aliases, requiredCXXAliases());
addAliases(ES, Aliases, standardRuntimeUtilityAliases());
return Aliases;
}
Expand All @@ -282,7 +318,8 @@ ArrayRef<std::pair<const char *, const char *>>
COFFPlatform::requiredCXXAliases() {
static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
{"_CxxThrowException", "__orc_rt_coff_cxx_throw_exception"},
};
{"_onexit", "__orc_rt_coff_onexit_per_jd"},
{"atexit", "__orc_rt_coff_atexit_per_jd"}};

return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
}
Expand Down Expand Up @@ -311,16 +348,37 @@ bool COFFPlatform::supportedTarget(const Triple &TT) {
}
}

COFFPlatform::COFFPlatform(
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD,
std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
LoadDynamicLibrary LoadDynLibrary, const char *VCRuntimePath, Error &Err)
COFFPlatform::COFFPlatform(ExecutionSession &ES,
ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
LoadDynamicLibrary LoadDynLibrary,
bool StaticVCRuntime, const char *VCRuntimePath,
Error &Err)
: ES(ES), ObjLinkingLayer(ObjLinkingLayer),
LoadDynLibrary(std::move(LoadDynLibrary)),
StaticVCRuntime(StaticVCRuntime),
COFFHeaderStartSymbol(ES.intern("__ImageBase")) {
ErrorAsOutParameter _(&Err);

// Create a generator for the ORC runtime archive.
auto OrcRuntimeArchiveGenerator =
StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
if (!OrcRuntimeArchiveGenerator) {
Err = std::move(OrcRuntimeArchiveGenerator.takeError());
return;
}

auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath);
if (!ArchiveBuffer) {
Err = createFileError(OrcRuntimePath, ArchiveBuffer.getError());
return;
}
OrcRuntimeArchiveBuffer = std::move(*ArchiveBuffer);
OrcRuntimeArchive =
std::make_unique<object::Archive>(*OrcRuntimeArchiveBuffer, Err);
if (Err)
return;

Bootstrapping.store(true);
ObjLinkingLayer.addPlugin(std::make_unique<COFFPlatformPlugin>(*this));

Expand All @@ -333,10 +391,12 @@ COFFPlatform::COFFPlatform(
}
VCRuntimeBootstrap = std::move(*VCRT);

for (auto &Lib : OrcRuntimeGenerator->getImportedDynamicLibraries())
for (auto &Lib : (*OrcRuntimeArchiveGenerator)->getImportedDynamicLibraries())
DylibsToPreload.insert(Lib);

auto ImportedLibs = VCRuntimeBootstrap->loadStaticVCRuntime(PlatformJD);
auto ImportedLibs =
StaticVCRuntime ? VCRuntimeBootstrap->loadStaticVCRuntime(PlatformJD)
: VCRuntimeBootstrap->loadDynamicVCRuntime(PlatformJD);
if (!ImportedLibs) {
Err = ImportedLibs.takeError();
return;
Expand All @@ -345,40 +405,43 @@ COFFPlatform::COFFPlatform(
for (auto &Lib : *ImportedLibs)
DylibsToPreload.insert(Lib);

PlatformJD.addGenerator(std::move(*OrcRuntimeArchiveGenerator));

// PlatformJD hasn't been set up by the platform yet (since we're creating
// the platform now), so set it up.
if (auto E2 = setupJITDylib(PlatformJD)) {
Err = std::move(E2);
return;
}

PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
}

Error COFFPlatform::bootstrap(JITDylib &PlatformJD) {
for (auto &Lib : DylibsToPreload)
if (auto Err = LoadDynLibrary(PlatformJD, Lib))
return Err;
for (auto& Lib : DylibsToPreload)
if (auto E2 = LoadDynLibrary(PlatformJD, Lib)) {
Err = std::move(E2);
return;
}

if (auto Err = VCRuntimeBootstrap->initializeStaticVCRuntime(PlatformJD))
return Err;
if (StaticVCRuntime)
if (auto E2 = VCRuntimeBootstrap->initializeStaticVCRuntime(PlatformJD)) {
Err = std::move(E2);
return;
}

// Associate wrapper function tags with JIT-side function implementations.
if (auto Err = associateRuntimeSupportFunctions(PlatformJD)) {
return Err;
if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
Err = std::move(E2);
return;
}

// Lookup addresses of runtime functions callable by the platform,
// call the platform bootstrap function to initialize the platform-state
// object in the executor.
if (auto Err = bootstrapCOFFRuntime(PlatformJD)) {
return Err;
if (auto E2 = bootstrapCOFFRuntime(PlatformJD)) {
Err = std::move(E2);
return;
}

Bootstrapping.store(false);
JDBootstrapStates.clear();

return Error::success();
}

Expected<COFFPlatform::JITDylibDepMap>
Expand Down Expand Up @@ -632,13 +695,6 @@ Error COFFPlatform::bootstrapCOFFRuntime(JITDylib &PlatformJD) {
}))
return Err;

// Run static initializers collected in bootstrap stage.
for (auto KV : JDBootstrapStates) {
auto &JDBState = KV.second;
if (auto Err = runBootstrapInitializers(JDBState))
return Err;
}

// Call bootstrap functions
if (auto Err = ES.callSPSWrapper<void()>(orc_rt_coff_platform_bootstrap))
return Err;
Expand All @@ -660,6 +716,13 @@ Error COFFPlatform::bootstrapCOFFRuntime(JITDylib &PlatformJD) {
return Err;
}

// Run static initializers collected in bootstrap stage.
for (auto KV : JDBootstrapStates) {
auto &JDBState = KV.second;
if (auto Err = runBootstrapInitializers(JDBState))
return Err;
}

return Error::success();
}

Expand Down
54 changes: 54 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,53 @@ Function *addHelperAndWrapper(Module &M, StringRef WrapperName,
return WrapperFn;
}

class ORCPlatformSupport : public LLJIT::PlatformSupport {
public:
ORCPlatformSupport(orc::LLJIT &J) : J(J) {}

Error initialize(orc::JITDylib &JD) override {
using llvm::orc::shared::SPSExecutorAddr;
using llvm::orc::shared::SPSString;
using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
enum dlopen_mode : int32_t {
ORC_RT_RTLD_LAZY = 0x1,
ORC_RT_RTLD_NOW = 0x2,
ORC_RT_RTLD_LOCAL = 0x4,
ORC_RT_RTLD_GLOBAL = 0x8
};

if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlopen_wrapper")) {
return J.getExecutionSession().callSPSWrapper<SPSDLOpenSig>(
*WrapperAddr, DSOHandles[&JD], JD.getName(),
int32_t(ORC_RT_RTLD_LAZY));
} else
return WrapperAddr.takeError();
}

Error deinitialize(orc::JITDylib &JD) override {
using llvm::orc::shared::SPSExecutorAddr;
using SPSDLCloseSig = int32_t(SPSExecutorAddr);

if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlclose_wrapper")) {
int32_t result;
auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>(
*WrapperAddr, result, DSOHandles[&JD]);
if (E)
return E;
else if (result)
return make_error<StringError>("dlclose failed",
inconvertibleErrorCode());
DSOHandles.erase(&JD);
} else
return WrapperAddr.takeError();
return Error::success();
}

private:
orc::LLJIT &J;
DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
};

class GenericLLVMIRPlatformSupport;

/// orc::Platform component of Generic LLVM IR Platform support.
Expand Down Expand Up @@ -880,6 +927,13 @@ Error LLJIT::applyDataLayout(Module &M) {
return Error::success();
}

Error setUpOrcPlatform(LLJIT& J) {
LLVM_DEBUG(
{ dbgs() << "Setting up orc platform support for LLJIT\n"; });
J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));
return Error::success();
}

void setUpGenericLLVMIRPlatform(LLJIT &J) {
LLVM_DEBUG(
{ dbgs() << "Setting up GenericLLVMIRPlatform support for LLJIT\n"; });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# RUN: llvm-jitlink -noexec \
# RUN: -slab-allocate 100Kb -slab-address 0xfff00000 -slab-page-size 4096 \
# RUN: -abs external_data=0xdeadbeef \
# RUN: -abs extern_out_of_range32=0x7fff00000000 \
# RUN: -check %s %t/coff_sm_reloc.o

.text
Expand Down Expand Up @@ -40,21 +39,6 @@ test_rel32_func:
test_rel32_data:
leaq named_data(%rip), %rax

# Check a dllimport stub for target out of reach is created as a GOT entry.
# jitlink-check: decode_operand(test_call_dllimport, 3) = \
# jitlink-check: got_addr(coff_sm_reloc.o, extern_out_of_range32) - \
# jitlink-check: next_pc(test_call_dllimport)
# jitlink-check: *{8}(got_addr(coff_sm_reloc.o, extern_out_of_range32)) = \
# jitlink-check: extern_out_of_range32
.def test_call_dllimport;
.scl 2;
.type 32;
.endef
.globl test_call_dllimport
.p2align 4, 0x90
test_call_dllimport:
callq *__imp_extern_out_of_range32(%rip)

# Check IMAGE_REL_AMD64_ADDR64 sets address of symbol to the fixup position.
# jitlink-check: *{8}(test_addr64) = named_data
.text
Expand Down
52 changes: 1 addition & 51 deletions llvm/tools/lli/lli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,53 +373,6 @@ class LLIObjectCache : public ObjectCache {
}
};

class ORCPlatformSupport : public orc::LLJIT::PlatformSupport {
public:
ORCPlatformSupport(orc::LLJIT &J) : J(J) {}

Error initialize(orc::JITDylib &JD) override {
using llvm::orc::shared::SPSExecutorAddr;
using llvm::orc::shared::SPSString;
using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
enum dlopen_mode : int32_t {
ORC_RT_RTLD_LAZY = 0x1,
ORC_RT_RTLD_NOW = 0x2,
ORC_RT_RTLD_LOCAL = 0x4,
ORC_RT_RTLD_GLOBAL = 0x8
};

if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlopen_wrapper")) {
return J.getExecutionSession().callSPSWrapper<SPSDLOpenSig>(
*WrapperAddr, DSOHandles[&JD], JD.getName(),
int32_t(ORC_RT_RTLD_LAZY));
} else
return WrapperAddr.takeError();
}

Error deinitialize(orc::JITDylib &JD) override {
using llvm::orc::shared::SPSExecutorAddr;
using SPSDLCloseSig = int32_t(SPSExecutorAddr);

if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlclose_wrapper")) {
int32_t result;
auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>(
*WrapperAddr, result, DSOHandles[&JD]);
if (E)
return E;
else if (result)
return make_error<StringError>("dlclose failed",
inconvertibleErrorCode());
DSOHandles.erase(&JD);
} else
return WrapperAddr.takeError();
return Error::success();
}

private:
orc::LLJIT &J;
DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
};

// On Mingw and Cygwin, an external symbol named '__main' is called from the
// generated 'main' function to allow static initialization. To avoid linking
// problems with remote targets (because lli's remote target support does not
Expand Down Expand Up @@ -969,10 +922,7 @@ int runOrcJIT(const char *ProgName) {
}
switch (P) {
case LLJITPlatform::ORC:
Builder.setPlatformSetUp([](llvm::orc::LLJIT &J) -> llvm::Error {
J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));
return Error::success();
});
Builder.setPlatformSetUp(orc::setUpOrcPlatform);
break;
case LLJITPlatform::GenericIR:
// Nothing to do: LLJITBuilder will use this by default.
Expand Down
15 changes: 5 additions & 10 deletions llvm/tools/llvm-jitlink/llvm-jitlink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1197,10 +1197,12 @@ Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err)
ExitOnErr(loadProcessSymbols(*this));
else {
// This symbol is used in testcases.
ExitOnErr(MainJD->define(absoluteSymbols(
auto &TestResultJD = ES.createBareJITDylib("<TestResultJD>");
ExitOnErr(TestResultJD.define(absoluteSymbols(
{{ES.intern("llvm_jitlink_setTestResultOverride"),
{pointerToJITTargetAddress(llvm_jitlink_setTestResultOverride),
JITSymbolFlags::Exported}}})));
MainJD->addToLinkOrder(TestResultJD);
}

ExitOnErr(loadDylibs(*this));
Expand Down Expand Up @@ -1237,16 +1239,9 @@ Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err)
};

if (auto P = COFFPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str(),
std::move(LoadDynLibrary))) {
// Set platform early to register jitdylib of dynamic libraries.
auto &CP = **P;
std::move(LoadDynLibrary)))
ES.setPlatform(std::move(*P));

if (auto E2 = CP.bootstrap(*MainJD)) {
Err = std::move(E2);
return;
}
} else {
else {
Err = P.takeError();
return;
}
Expand Down