[llvm] cdcc354 - [ORC][ORC-RT] Add initial Objective-C and Swift support to MachOPlatform.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 26 01:38:49 PDT 2021
Author: Lang Hames
Date: 2021-07-26T18:02:01+10:00
New Revision: cdcc35476833eca4f4996256e3ca0b21ecc26ad8
URL: https://github.com/llvm/llvm-project/commit/cdcc35476833eca4f4996256e3ca0b21ecc26ad8
DIFF: https://github.com/llvm/llvm-project/commit/cdcc35476833eca4f4996256e3ca0b21ecc26ad8.diff
LOG: [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).
Added:
compiler-rt/test/orc/TestCases/Darwin/x86-64/trivial-objc-methods.S
Modified:
compiler-rt/lib/orc/macho_platform.cpp
compiler-rt/lib/orc/macho_platform.h
llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
llvm/lib/ExecutionEngine/Orc/Mangling.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/orc/macho_platform.cpp b/compiler-rt/lib/orc/macho_platform.cpp
index c84ff78899321..2a960fb548fae 100644
--- a/compiler-rt/lib/orc/macho_platform.cpp
+++ b/compiler-rt/lib/orc/macho_platform.cpp
@@ -34,6 +34,36 @@ ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag)
extern "C" void __register_frame(const void *);
extern "C" void __deregister_frame(const void *);
+// Objective-C types.
+struct objc_class;
+struct objc_image_info;
+struct objc_object;
+struct objc_selector;
+
+using Class = objc_class *;
+using id = objc_object *;
+using SEL = objc_selector *;
+
+// Objective-C registration functions.
+// These are weakly imported. If the Objective-C runtime has not been loaded
+// then code containing Objective-C sections will generate an error.
+extern "C" id objc_msgSend(id, SEL, ...) ORC_RT_WEAK_IMPORT;
+extern "C" Class objc_readClassPair(Class,
+ const objc_image_info *) ORC_RT_WEAK_IMPORT;
+extern "C" SEL sel_registerName(const char *) ORC_RT_WEAK_IMPORT;
+
+// Swift types.
+class ProtocolRecord;
+class ProtocolConformanceRecord;
+
+extern "C" void
+swift_registerProtocols(const ProtocolRecord *begin,
+ const ProtocolRecord *end) ORC_RT_WEAK_IMPORT;
+
+extern "C" void swift_registerProtocolConformances(
+ const ProtocolConformanceRecord *begin,
+ const ProtocolConformanceRecord *end) ORC_RT_WEAK_IMPORT;
+
namespace {
template <typename HandleFDEFn>
@@ -70,6 +100,108 @@ Error validatePointerSectionExtent(const char *SectionName,
return Error::success();
}
+Error registerObjCSelectors(
+ const std::vector<ExecutorAddressRange> &ObjCSelRefsSections,
+ const MachOJITDylibInitializers &MOJDIs) {
+
+ if (ORC_RT_UNLIKELY(!sel_registerName))
+ return make_error<StringError>("sel_registerName is not available");
+
+ for (const auto &ObjCSelRefs : ObjCSelRefsSections) {
+
+ if (auto Err = validatePointerSectionExtent("__objc_selrefs", ObjCSelRefs))
+ return Err;
+
+ fprintf(stderr, "Processing selrefs section at 0x%llx\n",
+ ObjCSelRefs.StartAddress.getValue());
+ for (uintptr_t SelEntry : ObjCSelRefs.toSpan<uintptr_t>()) {
+ const char *SelName = reinterpret_cast<const char *>(SelEntry);
+ fprintf(stderr, "Registering selector \"%s\"\n", SelName);
+ auto Sel = sel_registerName(SelName);
+ *reinterpret_cast<SEL *>(SelEntry) = Sel;
+ }
+ }
+
+ return Error::success();
+}
+
+Error registerObjCClasses(
+ const std::vector<ExecutorAddressRange> &ObjCClassListSections,
+ const MachOJITDylibInitializers &MOJDIs) {
+
+ if (ObjCClassListSections.empty())
+ return Error::success();
+
+ if (ORC_RT_UNLIKELY(!objc_msgSend))
+ return make_error<StringError>("objc_msgSend is not available");
+ if (ORC_RT_UNLIKELY(!objc_readClassPair))
+ return make_error<StringError>("objc_readClassPair is not available");
+
+ struct ObjCClassCompiled {
+ void *Metaclass;
+ void *Parent;
+ void *Cache1;
+ void *Cache2;
+ void *Data;
+ };
+
+ auto *ImageInfo =
+ MOJDIs.ObjCImageInfoAddress.toPtr<const objc_image_info *>();
+ auto ClassSelector = sel_registerName("class");
+
+ for (const auto &ObjCClassList : ObjCClassListSections) {
+
+ if (auto Err =
+ validatePointerSectionExtent("__objc_classlist", ObjCClassList))
+ return Err;
+
+ for (uintptr_t ClassPtr : ObjCClassList.toSpan<uintptr_t>()) {
+ auto *Cls = reinterpret_cast<Class>(ClassPtr);
+ auto *ClassCompiled = reinterpret_cast<ObjCClassCompiled *>(ClassPtr);
+ objc_msgSend(reinterpret_cast<id>(ClassCompiled->Parent), ClassSelector);
+ auto Registered = objc_readClassPair(Cls, ImageInfo);
+
+ // FIXME: Improve diagnostic by reporting the failed class's name.
+ if (Registered != Cls)
+ return make_error<StringError>("Unable to register Objective-C class");
+ }
+ }
+ return Error::success();
+}
+
+Error registerSwift5Protocols(
+ const std::vector<ExecutorAddressRange> &Swift5ProtocolSections,
+ const MachOJITDylibInitializers &MOJDIs) {
+
+ if (ORC_RT_UNLIKELY(!Swift5ProtocolSections.empty() &&
+ !swift_registerProtocols))
+ return make_error<StringError>("swift_registerProtocols is not available");
+
+ for (const auto &Swift5Protocols : Swift5ProtocolSections)
+ swift_registerProtocols(
+ Swift5Protocols.StartAddress.toPtr<const ProtocolRecord *>(),
+ Swift5Protocols.EndAddress.toPtr<const ProtocolRecord *>());
+
+ return Error::success();
+}
+
+Error registerSwift5ProtocolConformances(
+ const std::vector<ExecutorAddressRange> &Swift5ProtocolConformanceSections,
+ const MachOJITDylibInitializers &MOJDIs) {
+
+ if (ORC_RT_UNLIKELY(!Swift5ProtocolConformanceSections.empty() &&
+ !swift_registerProtocolConformances))
+ return make_error<StringError>(
+ "swift_registerProtocolConformances is not available");
+
+ for (const auto &ProtoConfSec : Swift5ProtocolConformanceSections)
+ swift_registerProtocolConformances(
+ ProtoConfSec.StartAddress.toPtr<const ProtocolConformanceRecord *>(),
+ ProtoConfSec.EndAddress.toPtr<const ProtocolConformanceRecord *>());
+
+ return Error::success();
+}
+
Error runModInits(const std::vector<ExecutorAddressRange> &ModInitsSections,
const MachOJITDylibInitializers &MOJDIs) {
@@ -156,8 +288,12 @@ class MachOPlatformRuntimeState {
using InitSectionHandler =
Error (*)(const std::vector<ExecutorAddressRange> &Sections,
const MachOJITDylibInitializers &MOJDIs);
- const std::vector<std::pair<string_view, InitSectionHandler>> InitSections = {
- {"__DATA,__mod_init_func", runModInits}};
+ const std::vector<std::pair<const char *, InitSectionHandler>> InitSections =
+ {{"__DATA,__objc_selrefs", registerObjCSelectors},
+ {"__DATA,__objc_classlist", registerObjCClasses},
+ {"__TEXT,__swift5_protos", registerSwift5Protocols},
+ {"__TEXT,__swift5_proto", registerSwift5ProtocolConformances},
+ {"__DATA,__mod_init_func", runModInits}};
// FIXME: Move to thread-state.
std::string DLFcnError;
@@ -404,8 +540,7 @@ Error MachOPlatformRuntimeState::initializeJITDylib(
for (auto &KV : InitSections) {
const auto &Name = KV.first;
const auto &Handler = KV.second;
- // FIXME: Remove copy once we have C++17.
- auto I = MOJDIs.InitSections.find(to_string(Name));
+ auto I = MOJDIs.InitSections.find(Name);
if (I != MOJDIs.InitSections.end()) {
if (auto Err = Handler(I->second, MOJDIs))
return Err;
diff --git a/compiler-rt/lib/orc/macho_platform.h b/compiler-rt/lib/orc/macho_platform.h
index e097c1515ed17..6c05e844b0cd9 100644
--- a/compiler-rt/lib/orc/macho_platform.h
+++ b/compiler-rt/lib/orc/macho_platform.h
@@ -47,6 +47,7 @@ struct MachOJITDylibInitializers {
std::string Name;
ExecutorAddress MachOHeaderAddress;
+ ExecutorAddress ObjCImageInfoAddress;
std::unordered_map<std::string, SectionList> InitSections;
};
@@ -97,7 +98,7 @@ using SPSNamedExecutorAddressRangeSequenceMap =
SPSSequence<SPSTuple<SPSString, SPSExecutorAddressRangeSequence>>;
using SPSMachOJITDylibInitializers =
- SPSTuple<SPSString, SPSExecutorAddress,
+ SPSTuple<SPSString, SPSExecutorAddress, SPSExecutorAddress,
SPSNamedExecutorAddressRangeSequenceMap>;
using SPSMachOJITDylibInitializerSequence =
@@ -110,19 +111,22 @@ class SPSSerializationTraits<SPSMachOJITDylibInitializers,
public:
static size_t size(const macho::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 macho::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,
macho::MachOJITDylibInitializers &MOJDIs) {
return SPSMachOJITDylibInitializers::AsArgList::deserialize(
- IB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.InitSections);
+ IB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress,
+ MOJDIs.InitSections);
}
};
diff --git a/compiler-rt/test/orc/TestCases/Darwin/x86-64/trivial-objc-methods.S b/compiler-rt/test/orc/TestCases/Darwin/x86-64/trivial-objc-methods.S
new file mode 100644
index 0000000000000..5934630aeccf2
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Darwin/x86-64/trivial-objc-methods.S
@@ -0,0 +1,157 @@
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink -dlopen libobjc.A.dylib %t
+//
+// Test that Objective-C class and instance methods work.
+
+ .section __TEXT,__text,regular,pure_instructions
+ .build_version macos, 11, 0 sdk_version 11, 5
+ .p2align 4, 0x90
+"-[ZeroGen objZero]":
+ pushq %rbp
+ movq %rsp, %rbp
+ xorl %eax, %eax
+ popq %rbp
+ retq
+
+ .p2align 4, 0x90
+"+[ZeroGen classZero]":
+ pushq %rbp
+ movq %rsp, %rbp
+ xorl %eax, %eax
+ popq %rbp
+ retq
+
+ .globl _main
+ .p2align 4, 0x90
+_main:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _OBJC_CLASSLIST_REFERENCES_$_(%rip), %rdi
+ callq _objc_alloc_init
+ movq _OBJC_SELECTOR_REFERENCES_(%rip), %rsi
+ movq %rax, %rdi
+ callq *_objc_msgSend at GOTPCREL(%rip)
+ testl %eax, %eax
+ jne LBB2_3
+
+ movq _OBJC_CLASSLIST_REFERENCES_$_(%rip), %rdi
+ movq _OBJC_SELECTOR_REFERENCES_.2(%rip), %rsi
+ callq *_objc_msgSend at GOTPCREL(%rip)
+ testl %eax, %eax
+ je LBB2_2
+LBB2_3:
+ movl $1, %eax
+ popq %rbp
+ retq
+LBB2_2:
+ xorl %eax, %eax
+ popq %rbp
+ retq
+
+ .section __TEXT,__objc_classname,cstring_literals
+L_OBJC_CLASS_NAME_:
+ .asciz "ZeroGen"
+
+ .section __TEXT,__objc_methname,cstring_literals
+L_OBJC_METH_VAR_NAME_:
+ .asciz "classZero"
+
+ .section __TEXT,__objc_methtype,cstring_literals
+L_OBJC_METH_VAR_TYPE_:
+ .asciz "i16 at 0:8"
+
+ .section __DATA,__objc_const
+ .p2align 3
+__OBJC_$_CLASS_METHODS_ZeroGen:
+ .long 24
+ .long 1
+ .quad L_OBJC_METH_VAR_NAME_
+ .quad L_OBJC_METH_VAR_TYPE_
+ .quad "+[ZeroGen classZero]"
+
+ .p2align 3
+__OBJC_METACLASS_RO_$_ZeroGen:
+ .long 1
+ .long 40
+ .long 40
+ .space 4
+ .quad 0
+ .quad L_OBJC_CLASS_NAME_
+ .quad __OBJC_$_CLASS_METHODS_ZeroGen
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+ .section __DATA,__objc_data
+ .globl _OBJC_METACLASS_$_ZeroGen
+ .p2align 3
+_OBJC_METACLASS_$_ZeroGen:
+ .quad _OBJC_METACLASS_$_NSObject
+ .quad _OBJC_METACLASS_$_NSObject
+ .quad __objc_empty_cache
+ .quad 0
+ .quad __OBJC_METACLASS_RO_$_ZeroGen
+
+ .section __TEXT,__objc_methname,cstring_literals
+L_OBJC_METH_VAR_NAME_.1:
+ .asciz "objZero"
+
+ .section __DATA,__objc_const
+ .p2align 3
+__OBJC_$_INSTANCE_METHODS_ZeroGen:
+ .long 24
+ .long 1
+ .quad L_OBJC_METH_VAR_NAME_.1
+ .quad L_OBJC_METH_VAR_TYPE_
+ .quad "-[ZeroGen objZero]"
+
+ .p2align 3
+__OBJC_CLASS_RO_$_ZeroGen:
+ .long 0
+ .long 8
+ .long 8
+ .space 4
+ .quad 0
+ .quad L_OBJC_CLASS_NAME_
+ .quad __OBJC_$_INSTANCE_METHODS_ZeroGen
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+ .section __DATA,__objc_data
+ .globl _OBJC_CLASS_$_ZeroGen
+ .p2align 3
+_OBJC_CLASS_$_ZeroGen:
+ .quad _OBJC_METACLASS_$_ZeroGen
+ .quad _OBJC_CLASS_$_NSObject
+ .quad __objc_empty_cache
+ .quad 0
+ .quad __OBJC_CLASS_RO_$_ZeroGen
+
+ .section __DATA,__objc_classrefs,regular,no_dead_strip
+ .p2align 3
+_OBJC_CLASSLIST_REFERENCES_$_:
+ .quad _OBJC_CLASS_$_ZeroGen
+
+ .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
+ .p2align 3
+_OBJC_SELECTOR_REFERENCES_:
+ .quad L_OBJC_METH_VAR_NAME_.1
+
+ .p2align 3
+_OBJC_SELECTOR_REFERENCES_.2:
+ .quad L_OBJC_METH_VAR_NAME_
+
+ .section __DATA,__objc_classlist,regular,no_dead_strip
+ .p2align 3
+L_OBJC_LABEL_CLASS_$:
+ .quad _OBJC_CLASS_$_ZeroGen
+
+ .section __DATA,__objc_imageinfo,regular,no_dead_strip
+L_OBJC_IMAGE_INFO:
+ .long 0
+ .long 64
+
+.subsections_via_symbols
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
index 189ff80a199fb..8b228a52244d1 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
@@ -42,6 +42,7 @@ struct MachOJITDylibInitializers {
std::string Name;
ExecutorAddress MachOHeaderAddress;
+ ExecutorAddress ObjCImageInfoAddress;
StringMap<SectionList> InitSections;
};
@@ -121,6 +122,9 @@ class MachOPlatform : public Platform {
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 @@ class MachOPlatform : public Platform {
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 @@ class MachOPlatform : public Platform {
// 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);
}
};
diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
index e07d8f7c9b82d..986f39a883280 100644
--- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
@@ -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(
diff --git a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
index 606304741cf75..14b22880ab7ec 100644
--- a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
@@ -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;
}
}
More information about the llvm-commits
mailing list