[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