1
0
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:
Lang Hames 2021-07-26 17:49:05 +10:00
parent 0b2bb4e657
commit 480ddba43e
3 changed files with 152 additions and 22 deletions

View File

@ -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);
}
};

View File

@ -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(

View File

@ -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;
}
}