mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[ORC][ORC-RT] Add initial Objective-C and Swift support to MachOPlatform.
This allows ORC to execute code containing Objective-C and Swift classes and methods (provided that the language runtime is loaded into the executor).
This commit is contained in:
parent
0b2bb4e657
commit
480ddba43e
@ -42,6 +42,7 @@ struct MachOJITDylibInitializers {
|
||||
|
||||
std::string Name;
|
||||
ExecutorAddress MachOHeaderAddress;
|
||||
ExecutorAddress ObjCImageInfoAddress;
|
||||
|
||||
StringMap<SectionList> InitSections;
|
||||
};
|
||||
@ -121,6 +122,9 @@ public:
|
||||
static ArrayRef<std::pair<const char *, const char *>>
|
||||
standardRuntimeUtilityAliases();
|
||||
|
||||
/// Returns true if the given section name is an initializer section.
|
||||
static bool isInitializerSection(StringRef SegName, StringRef SectName);
|
||||
|
||||
private:
|
||||
// The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO
|
||||
// platform features including initializers, exceptions, TLV, and language
|
||||
@ -165,12 +169,16 @@ private:
|
||||
Error preserveInitSections(jitlink::LinkGraph &G,
|
||||
MaterializationResponsibility &MR);
|
||||
|
||||
Error processObjCImageInfo(jitlink::LinkGraph &G,
|
||||
MaterializationResponsibility &MR);
|
||||
|
||||
Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD);
|
||||
|
||||
Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
|
||||
|
||||
std::mutex PluginMutex;
|
||||
MachOPlatform &MP;
|
||||
DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos;
|
||||
InitSymbolDepMap InitSymbolDeps;
|
||||
};
|
||||
|
||||
@ -211,7 +219,7 @@ private:
|
||||
// Records the addresses of runtime symbols used by the platform.
|
||||
Error bootstrapMachORuntime(JITDylib &PlatformJD);
|
||||
|
||||
Error registerInitInfo(JITDylib &JD,
|
||||
Error registerInitInfo(JITDylib &JD, ExecutorAddress ObjCImageInfoAddr,
|
||||
ArrayRef<jitlink::Section *> InitSections);
|
||||
|
||||
Error registerPerObjectSections(const MachOPerObjectSectionsToRegister &POSR);
|
||||
@ -274,7 +282,7 @@ using SPSNamedExecutorAddressRangeSequenceMap =
|
||||
SPSSequence<SPSTuple<SPSString, SPSExecutorAddressRangeSequence>>;
|
||||
|
||||
using SPSMachOJITDylibInitializers =
|
||||
SPSTuple<SPSString, SPSExecutorAddress,
|
||||
SPSTuple<SPSString, SPSExecutorAddress, SPSExecutorAddress,
|
||||
SPSNamedExecutorAddressRangeSequenceMap>;
|
||||
|
||||
using SPSMachOJITDylibInitializerSequence =
|
||||
@ -287,19 +295,22 @@ class SPSSerializationTraits<SPSMachOJITDylibInitializers,
|
||||
public:
|
||||
static size_t size(const MachOJITDylibInitializers &MOJDIs) {
|
||||
return SPSMachOJITDylibInitializers::AsArgList::size(
|
||||
MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.InitSections);
|
||||
MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress,
|
||||
MOJDIs.InitSections);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &OB,
|
||||
const MachOJITDylibInitializers &MOJDIs) {
|
||||
return SPSMachOJITDylibInitializers::AsArgList::serialize(
|
||||
OB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.InitSections);
|
||||
OB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress,
|
||||
MOJDIs.InitSections);
|
||||
}
|
||||
|
||||
static bool deserialize(SPSInputBuffer &IB,
|
||||
MachOJITDylibInitializers &MOJDIs) {
|
||||
return SPSMachOJITDylibInitializers::AsArgList::deserialize(
|
||||
IB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.InitSections);
|
||||
IB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress,
|
||||
MOJDIs.InitSections);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -128,11 +128,18 @@ constexpr MachOHeaderMaterializationUnit::HeaderSymbol
|
||||
|
||||
StringRef EHFrameSectionName = "__TEXT,__eh_frame";
|
||||
StringRef ModInitFuncSectionName = "__DATA,__mod_init_func";
|
||||
StringRef ObjCClassListSectionName = "__DATA,__objc_classlist";
|
||||
StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info";
|
||||
StringRef ObjCSelRefsSectionName = "__DATA,__objc_selrefs";
|
||||
StringRef Swift5ProtoSectionName = "__TEXT,__swift5_proto";
|
||||
StringRef Swift5ProtosSectionName = "__TEXT,__swift5_protos";
|
||||
StringRef ThreadBSSSectionName = "__DATA,__thread_bss";
|
||||
StringRef ThreadDataSectionName = "__DATA,__thread_data";
|
||||
StringRef ThreadVarsSectionName = "__DATA,__thread_vars";
|
||||
|
||||
StringRef InitSectionNames[] = {ModInitFuncSectionName};
|
||||
StringRef InitSectionNames[] = {
|
||||
ModInitFuncSectionName, ObjCSelRefsSectionName, ObjCClassListSectionName,
|
||||
Swift5ProtosSectionName, Swift5ProtoSectionName};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
@ -246,6 +253,15 @@ MachOPlatform::standardRuntimeUtilityAliases() {
|
||||
StandardRuntimeUtilityAliases);
|
||||
}
|
||||
|
||||
bool MachOPlatform::isInitializerSection(StringRef SegName,
|
||||
StringRef SectName) {
|
||||
for (auto &Name : InitSectionNames) {
|
||||
if (Name.startswith(SegName) && Name.substr(7) == SectName)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MachOPlatform::supportedTarget(const Triple &TT) {
|
||||
switch (TT.getArch()) {
|
||||
case Triple::x86_64:
|
||||
@ -525,7 +541,8 @@ Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) {
|
||||
}
|
||||
|
||||
Error MachOPlatform::registerInitInfo(
|
||||
JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) {
|
||||
JITDylib &JD, ExecutorAddress ObjCImageInfoAddr,
|
||||
ArrayRef<jitlink::Section *> InitSections) {
|
||||
|
||||
std::unique_lock<std::mutex> Lock(PlatformMutex);
|
||||
|
||||
@ -550,6 +567,8 @@ Error MachOPlatform::registerInitInfo(
|
||||
InitSeq = &I->second;
|
||||
}
|
||||
|
||||
InitSeq->ObjCImageInfoAddress = ObjCImageInfoAddr;
|
||||
|
||||
for (auto *Sec : InitSections) {
|
||||
// FIXME: Avoid copy here.
|
||||
jitlink::SectionRange R(*Sec);
|
||||
@ -631,7 +650,9 @@ void MachOPlatform::MachOPlatformPlugin::addInitializerSupportPasses(
|
||||
|
||||
/// Preserve init sections.
|
||||
Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) {
|
||||
return preserveInitSections(G, MR);
|
||||
if (auto Err = preserveInitSections(G, MR))
|
||||
return Err;
|
||||
return processObjCImageInfo(G, MR);
|
||||
});
|
||||
|
||||
Config.PostFixupPasses.push_back(
|
||||
@ -768,11 +789,95 @@ Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
|
||||
jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
|
||||
|
||||
// If there's an ObjC imagine info then either
|
||||
// (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
|
||||
// this case we name and record it.
|
||||
// OR
|
||||
// (2) We already have a recorded __objc_imageinfo for this JITDylib,
|
||||
// in which case we just verify it.
|
||||
auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName);
|
||||
if (!ObjCImageInfo)
|
||||
return Error::success();
|
||||
|
||||
auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
|
||||
|
||||
// Check that the section is not empty if present.
|
||||
if (llvm::empty(ObjCImageInfoBlocks))
|
||||
return make_error<StringError>("Empty " + ObjCImageInfoSectionName +
|
||||
" section in " + G.getName(),
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// Check that there's only one block in the section.
|
||||
if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
|
||||
return make_error<StringError>("Multiple blocks in " +
|
||||
ObjCImageInfoSectionName +
|
||||
" section in " + G.getName(),
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// Check that the __objc_imageinfo section is unreferenced.
|
||||
// FIXME: We could optimize this check if Symbols had a ref-count.
|
||||
for (auto &Sec : G.sections()) {
|
||||
if (&Sec != ObjCImageInfo)
|
||||
for (auto *B : Sec.blocks())
|
||||
for (auto &E : B->edges())
|
||||
if (E.getTarget().isDefined() &&
|
||||
&E.getTarget().getBlock().getSection() == ObjCImageInfo)
|
||||
return make_error<StringError>(ObjCImageInfoSectionName +
|
||||
" is referenced within file " +
|
||||
G.getName(),
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
|
||||
auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
|
||||
auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
|
||||
auto Flags =
|
||||
support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
|
||||
|
||||
// Lock the mutex while we verify / update the ObjCImageInfos map.
|
||||
std::lock_guard<std::mutex> Lock(PluginMutex);
|
||||
|
||||
auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
|
||||
if (ObjCImageInfoItr != ObjCImageInfos.end()) {
|
||||
// We've already registered an __objc_imageinfo section. Verify the
|
||||
// content of this new section matches, then delete it.
|
||||
if (ObjCImageInfoItr->second.first != Version)
|
||||
return make_error<StringError>(
|
||||
"ObjC version in " + G.getName() +
|
||||
" does not match first registered version",
|
||||
inconvertibleErrorCode());
|
||||
if (ObjCImageInfoItr->second.second != Flags)
|
||||
return make_error<StringError>("ObjC flags in " + G.getName() +
|
||||
" do not match first registered flags",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// __objc_imageinfo is valid. Delete the block.
|
||||
for (auto *S : ObjCImageInfo->symbols())
|
||||
G.removeDefinedSymbol(*S);
|
||||
G.removeBlock(ObjCImageInfoBlock);
|
||||
} else {
|
||||
// We haven't registered an __objc_imageinfo section yet. Register and
|
||||
// move on. The section should already be marked no-dead-strip.
|
||||
ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MachOPlatform::MachOPlatformPlugin::registerInitSections(
|
||||
jitlink::LinkGraph &G, JITDylib &JD) {
|
||||
|
||||
ExecutorAddress ObjCImageInfoAddr;
|
||||
SmallVector<jitlink::Section *> InitSections;
|
||||
|
||||
if (auto *ObjCImageInfoSec = G.findSectionByName(ObjCImageInfoSectionName)) {
|
||||
if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart())
|
||||
ObjCImageInfoAddr.setValue(Addr);
|
||||
}
|
||||
|
||||
for (auto InitSectionName : InitSectionNames)
|
||||
if (auto *Sec = G.findSectionByName(InitSectionName))
|
||||
InitSections.push_back(Sec);
|
||||
@ -780,6 +885,9 @@ Error MachOPlatform::MachOPlatformPlugin::registerInitSections(
|
||||
// Dump the scraped inits.
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
|
||||
if (ObjCImageInfoAddr)
|
||||
dbgs() << " " << ObjCImageInfoSectionName << ": "
|
||||
<< formatv("{0:x}", ObjCImageInfoAddr.getValue()) << "\n";
|
||||
for (auto *Sec : InitSections) {
|
||||
jitlink::SectionRange R(*Sec);
|
||||
dbgs() << " " << Sec->getName() << ": "
|
||||
@ -787,7 +895,7 @@ Error MachOPlatform::MachOPlatformPlugin::registerInitSections(
|
||||
}
|
||||
});
|
||||
|
||||
return MP.registerInitInfo(JD, InitSections);
|
||||
return MP.registerInitInfo(JD, ObjCImageInfoAddr, InitSections);
|
||||
}
|
||||
|
||||
Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
|
||||
|
@ -7,6 +7,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Mangling.h"
|
||||
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/Object/MachO.h"
|
||||
@ -130,24 +131,34 @@ getObjectSymbolInfo(ExecutionSession &ES, MemoryBufferRef ObjBuffer) {
|
||||
|
||||
SymbolStringPtr InitSymbol;
|
||||
|
||||
size_t Counter = 0;
|
||||
auto AddInitSymbol = [&]() {
|
||||
while (true) {
|
||||
std::string InitSymString;
|
||||
raw_string_ostream(InitSymString)
|
||||
<< "$." << ObjBuffer.getBufferIdentifier() << ".__inits."
|
||||
<< Counter++;
|
||||
InitSymbol = ES.intern(InitSymString);
|
||||
if (SymbolFlags.count(InitSymbol))
|
||||
continue;
|
||||
SymbolFlags[InitSymbol] = JITSymbolFlags::MaterializationSideEffectsOnly;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if (IsMachO) {
|
||||
auto &MachOObj = cast<object::MachOObjectFile>(*Obj->get());
|
||||
for (auto &Sec : MachOObj.sections()) {
|
||||
auto SecType = MachOObj.getSectionType(Sec);
|
||||
if ((SecType & MachO::SECTION_TYPE) == MachO::S_MOD_INIT_FUNC_POINTERS) {
|
||||
size_t Counter = 0;
|
||||
while (true) {
|
||||
std::string InitSymString;
|
||||
raw_string_ostream(InitSymString)
|
||||
<< "$." << ObjBuffer.getBufferIdentifier() << ".__inits."
|
||||
<< Counter++;
|
||||
InitSymbol = ES.intern(InitSymString);
|
||||
if (SymbolFlags.count(InitSymbol))
|
||||
continue;
|
||||
SymbolFlags[InitSymbol] =
|
||||
JITSymbolFlags::MaterializationSideEffectsOnly;
|
||||
break;
|
||||
}
|
||||
AddInitSymbol();
|
||||
break;
|
||||
}
|
||||
auto SegName =
|
||||
MachOObj.getSectionFinalSegmentName(Sec.getRawDataRefImpl());
|
||||
auto SecName = cantFail(MachOObj.getSectionName(Sec.getRawDataRefImpl()));
|
||||
if (MachOPlatform::isInitializerSection(SegName, SecName)) {
|
||||
AddInitSymbol();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user