ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_initializers_tag)
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag)
-// 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 *;
+struct mach_header;
// 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;
-class TypeMetadataRecord;
-
extern "C" void
-swift_registerProtocols(const ProtocolRecord *begin,
- const ProtocolRecord *end) ORC_RT_WEAK_IMPORT;
+_objc_map_images(unsigned count, const char *const paths[],
+ const mach_header *const mhdrs[]) ORC_RT_WEAK_IMPORT;
-extern "C" void swift_registerProtocolConformances(
- const ProtocolConformanceRecord *begin,
- const ProtocolConformanceRecord *end) ORC_RT_WEAK_IMPORT;
-
-extern "C" void swift_registerTypeMetadataRecords(
- const TypeMetadataRecord *begin,
- const TypeMetadataRecord *end) ORC_RT_WEAK_IMPORT;
+extern "C" void _objc_load_image(const char *path,
+ const mach_header *mh) ORC_RT_WEAK_IMPORT;
// Libunwind prototypes.
struct unw_dynamic_unwind_sections {
std::unordered_map<void *, size_t> ZeroInitRanges;
UnwindSectionsMap UnwindSections;
RecordSectionsTracker<void (*)()> ModInitsSections;
- RecordSectionsTracker<void *> ObjCClassListSections;
- RecordSectionsTracker<void *> ObjCSelRefsSections;
- RecordSectionsTracker<char> Swift5ProtocolsSections;
- RecordSectionsTracker<char> Swift5ProtocolConformancesSections;
- RecordSectionsTracker<char> Swift5TypesSections;
+ RecordSectionsTracker<char> ObjCRuntimeRegistrationObjects;
bool referenced() const {
return LinkedAgainstRefCount != 0 || DlRefCount != 0;
static Error registerEHFrames(span<const char> EHFrameSection);
static Error deregisterEHFrames(span<const char> EHFrameSection);
- static Error registerObjCSelectors(JITDylibState &JDS);
- static Error registerObjCClasses(JITDylibState &JDS);
- static Error registerSwift5Protocols(JITDylibState &JDS);
- static Error registerSwift5ProtocolConformances(JITDylibState &JDS);
- static Error registerSwift5Types(JITDylibState &JDS);
+ static Error registerObjCRegistrationObjects(JITDylibState &JDS);
static Error runModInits(std::unique_lock<std::mutex> &JDStatesLock,
JITDylibState &JDS);
JDS->DataSectionContent[KV.second.Start.toPtr<char *>()] =
std::vector<char>(S.begin(), S.end());
} else if (KV.first == "__DATA,__common") {
- // fprintf(stderr, "Adding zero-init range %llx -- %llx\n",
- // KV.second.Start.getValue(), KV.second.size());
JDS->ZeroInitRanges[KV.second.Start.toPtr<char *>()] = KV.second.size();
} else if (KV.first == "__DATA,__thread_data") {
if (auto Err = registerThreadDataSection(KV.second.toSpan<const char>()))
return Err;
- } else if (KV.first == "__DATA,__objc_selrefs")
- JDS->ObjCSelRefsSections.add(KV.second.toSpan<void *>());
- else if (KV.first == "__DATA,__objc_classlist")
- JDS->ObjCClassListSections.add(KV.second.toSpan<void *>());
- else if (KV.first == "__TEXT,__swift5_protos")
- JDS->Swift5ProtocolsSections.add(KV.second.toSpan<char>());
- else if (KV.first == "__TEXT,__swift5_proto")
- JDS->Swift5ProtocolConformancesSections.add(KV.second.toSpan<char>());
- else if (KV.first == "__TEXT,__swift5_types")
- JDS->Swift5TypesSections.add(KV.second.toSpan<char>());
+ } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
+ JDS->ObjCRuntimeRegistrationObjects.add(KV.second.toSpan<char>());
else if (KV.first == "__DATA,__mod_init_func")
JDS->ModInitsSections.add(KV.second.toSpan<void (*)()>());
else {
if (auto Err =
deregisterThreadDataSection(KV.second.toSpan<const char>()))
return Err;
- } else if (KV.first == "__DATA,__objc_selrefs")
- JDS->ObjCSelRefsSections.removeIfPresent(KV.second);
- else if (KV.first == "__DATA,__objc_classlist")
- JDS->ObjCClassListSections.removeIfPresent(KV.second);
- else if (KV.first == "__TEXT,__swift5_protos")
- JDS->Swift5ProtocolsSections.removeIfPresent(KV.second);
- else if (KV.first == "__TEXT,__swift5_proto")
- JDS->Swift5ProtocolConformancesSections.removeIfPresent(KV.second);
- else if (KV.first == "__TEXT,__swift5_types")
- JDS->Swift5TypesSections.removeIfPresent(KV.second);
+ } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
+ JDS->ObjCRuntimeRegistrationObjects.removeIfPresent(KV.second);
else if (KV.first == "__DATA,__mod_init_func")
JDS->ModInitsSections.removeIfPresent(KV.second);
else {
return Error::success();
}
-Error MachOPlatformRuntimeState::registerObjCSelectors(JITDylibState &JDS) {
- if (!JDS.ObjCSelRefsSections.hasNewSections())
- return Error::success();
-
- if (ORC_RT_UNLIKELY(!sel_registerName))
- return make_error<StringError>("sel_registerName is not available");
-
- JDS.ObjCSelRefsSections.processNewSections([](span<void *> SelRefs) {
- for (void *&SelEntry : SelRefs) {
- const char *SelName = reinterpret_cast<const char *>(SelEntry);
- auto Sel = sel_registerName(SelName);
- *reinterpret_cast<SEL *>(&SelEntry) = Sel;
- }
- });
-
- return Error::success();
-}
-
-Error MachOPlatformRuntimeState::registerObjCClasses(JITDylibState &JDS) {
- if (!JDS.ObjCClassListSections.hasNewSections())
- 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 ClassSelector = sel_registerName("class");
-
- return JDS.ObjCClassListSections.processNewSections(
- [&](span<void *> ClassPtrs) -> Error {
- for (void *ClassPtr : ClassPtrs) {
- 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, JDS.ObjCImageInfo);
- // 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 MachOPlatformRuntimeState::registerSwift5Protocols(JITDylibState &JDS) {
-
- if (!JDS.Swift5ProtocolsSections.hasNewSections())
- return Error::success();
-
- if (ORC_RT_UNLIKELY(!swift_registerProtocols))
- return make_error<StringError>("swift_registerProtocols is not available");
-
- JDS.Swift5ProtocolsSections.processNewSections([](span<char> ProtoSec) {
- swift_registerProtocols(
- reinterpret_cast<const ProtocolRecord *>(ProtoSec.data()),
- reinterpret_cast<const ProtocolRecord *>(ProtoSec.data() +
- ProtoSec.size()));
- });
-
- return Error::success();
-}
-
-Error MachOPlatformRuntimeState::registerSwift5ProtocolConformances(
+Error MachOPlatformRuntimeState::registerObjCRegistrationObjects(
JITDylibState &JDS) {
-
- if (!JDS.Swift5ProtocolConformancesSections.hasNewSections())
- return Error::success();
-
- if (ORC_RT_UNLIKELY(!swift_registerProtocolConformances))
+ if (!_objc_map_images || !_objc_load_image)
return make_error<StringError>(
- "swift_registerProtocolConformances is not available");
-
- JDS.Swift5ProtocolConformancesSections.processNewSections(
- [](span<char> ProtoConfSec) {
- swift_registerProtocolConformances(
- reinterpret_cast<const ProtocolConformanceRecord *>(
- ProtoConfSec.data()),
- reinterpret_cast<const ProtocolConformanceRecord *>(
- ProtoConfSec.data() + ProtoConfSec.size()));
- });
+ "Could not register Objective-C / Swift metadata: _objc_map_images / "
+ "_objc_load_image not found");
- return Error::success();
-}
-
-Error MachOPlatformRuntimeState::registerSwift5Types(JITDylibState &JDS) {
+ std::vector<char *> RegObjBases;
+ JDS.ObjCRuntimeRegistrationObjects.processNewSections(
+ [&](span<char> RegObj) { RegObjBases.push_back(RegObj.data()); });
- if (!JDS.Swift5TypesSections.hasNewSections())
- return Error::success();
+ std::vector<char *> Paths;
+ Paths.resize(RegObjBases.size());
+ _objc_map_images(RegObjBases.size(), Paths.data(),
+ reinterpret_cast<mach_header **>(RegObjBases.data()));
- if (ORC_RT_UNLIKELY(!swift_registerTypeMetadataRecords))
- return make_error<StringError>(
- "swift_registerTypeMetadataRecords is not available");
-
- JDS.Swift5TypesSections.processNewSections([&](span<char> TypesSec) {
- swift_registerTypeMetadataRecords(
- reinterpret_cast<const TypeMetadataRecord *>(TypesSec.data()),
- reinterpret_cast<const TypeMetadataRecord *>(TypesSec.data() +
- TypesSec.size()));
- });
+ for (void *RegObjBase : RegObjBases)
+ _objc_load_image(nullptr, reinterpret_cast<mach_header *>(RegObjBase));
return Error::success();
}
}
// Initialize this JITDylib.
- if (auto Err = registerObjCSelectors(JDS))
- return Err;
- if (auto Err = registerObjCClasses(JDS))
- return Err;
- if (auto Err = registerSwift5Protocols(JDS))
- return Err;
- if (auto Err = registerSwift5ProtocolConformances(JDS))
- return Err;
- if (auto Err = registerSwift5Types(JDS))
+ if (auto Err = registerObjCRegistrationObjects(JDS))
return Err;
if (auto Err = runModInits(JDStatesLock, JDS))
return Err;
--- /dev/null
+// Test that we can handle calls to methods on categories.
+// The following assembly defines an ObjC class Foo with an instance method
+// -foo, then uses a category (Bar) to add an extra instance method -bar.
+// The main function calls both -foo and -bar on an instance of Foo to check
+// that the calls behave as expected.
+//
+// RUN: %clang -c -o %t.o %s
+// RUN: %llvm_jitlink -preload libobjc.A.dylib %t.o
+
+ .section __TEXT,__text,regular,pure_instructions
+ .build_version macos, 14, 0
+ .p2align 2
+"-[Foo foo]":
+ mov w0, #1
+ ret
+
+ .p2align 2
+"-[Foo(Bar) bar]":
+ mov w0, #1
+ ret
+
+ .globl _main
+ .p2align 2
+_main:
+ stp x20, x19, [sp, #-32]!
+ stp x29, x30, [sp, #16]
+ add x29, sp, #16
+Lloh0:
+ adrp x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGE
+Lloh1:
+ ldr x0, [x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGEOFF]
+ bl _objc_alloc_init
+ mov x19, x0
+Lloh2:
+ adrp x8, _OBJC_SELECTOR_REFERENCES_@PAGE
+Lloh3:
+ ldr x1, [x8, _OBJC_SELECTOR_REFERENCES_@PAGEOFF]
+ bl _objc_msgSend
+ cmp w0, #1
+ b.ne LBB2_2
+
+Lloh4:
+ adrp x8, _OBJC_SELECTOR_REFERENCES_.3@PAGE
+Lloh5:
+ ldr x1, [x8, _OBJC_SELECTOR_REFERENCES_.3@PAGEOFF]
+ mov x0, x19
+ bl _objc_msgSend
+ cmp w0, #1
+ cset w0, ne
+ ldp x29, x30, [sp, #16]
+ ldp x20, x19, [sp], #32
+ ret
+LBB2_2:
+ mov w0, #1
+ ldp x29, x30, [sp, #16]
+ ldp x20, x19, [sp], #32
+ ret
+ .loh AdrpLdr Lloh2, Lloh3
+ .loh AdrpLdr Lloh0, Lloh1
+ .loh AdrpLdr Lloh4, Lloh5
+
+ .section __TEXT,__objc_classname,cstring_literals
+l_OBJC_CLASS_NAME_:
+ .asciz "Foo"
+
+ .section __DATA,__objc_const
+ .p2align 3, 0x0
+__OBJC_METACLASS_RO_$_Foo:
+ .long 1
+ .long 40
+ .long 40
+ .space 4
+ .quad 0
+ .quad l_OBJC_CLASS_NAME_
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+ .section __DATA,__objc_data
+ .globl _OBJC_METACLASS_$_Foo
+ .p2align 3, 0x0
+_OBJC_METACLASS_$_Foo:
+ .quad _OBJC_METACLASS_$_NSObject
+ .quad _OBJC_METACLASS_$_NSObject
+ .quad __objc_empty_cache
+ .quad 0
+ .quad __OBJC_METACLASS_RO_$_Foo
+
+ .section __TEXT,__objc_methname,cstring_literals
+l_OBJC_METH_VAR_NAME_:
+ .asciz "foo"
+
+ .section __TEXT,__objc_methtype,cstring_literals
+l_OBJC_METH_VAR_TYPE_:
+ .asciz "i16@0:8"
+
+ .section __DATA,__objc_const
+ .p2align 3, 0x0
+__OBJC_$_INSTANCE_METHODS_Foo:
+ .long 24
+ .long 1
+ .quad l_OBJC_METH_VAR_NAME_
+ .quad l_OBJC_METH_VAR_TYPE_
+ .quad "-[Foo foo]"
+
+ .p2align 3, 0x0
+__OBJC_CLASS_RO_$_Foo:
+ .long 0
+ .long 8
+ .long 8
+ .space 4
+ .quad 0
+ .quad l_OBJC_CLASS_NAME_
+ .quad __OBJC_$_INSTANCE_METHODS_Foo
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+ .section __DATA,__objc_data
+ .globl _OBJC_CLASS_$_Foo
+ .p2align 3, 0x0
+_OBJC_CLASS_$_Foo:
+ .quad _OBJC_METACLASS_$_Foo
+ .quad _OBJC_CLASS_$_NSObject
+ .quad __objc_empty_cache
+ .quad 0
+ .quad __OBJC_CLASS_RO_$_Foo
+
+ .section __TEXT,__objc_classname,cstring_literals
+l_OBJC_CLASS_NAME_.1:
+ .asciz "Bar"
+
+ .section __TEXT,__objc_methname,cstring_literals
+l_OBJC_METH_VAR_NAME_.2:
+ .asciz "bar"
+
+ .section __DATA,__objc_const
+ .p2align 3, 0x0
+__OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Bar:
+ .long 24
+ .long 1
+ .quad l_OBJC_METH_VAR_NAME_.2
+ .quad l_OBJC_METH_VAR_TYPE_
+ .quad "-[Foo(Bar) bar]"
+
+ .p2align 3, 0x0
+__OBJC_$_CATEGORY_Foo_$_Bar:
+ .quad l_OBJC_CLASS_NAME_.1
+ .quad _OBJC_CLASS_$_Foo
+ .quad __OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Bar
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .long 64
+ .space 4
+
+ .section __DATA,__objc_classrefs,regular,no_dead_strip
+ .p2align 3, 0x0
+_OBJC_CLASSLIST_REFERENCES_$_:
+ .quad _OBJC_CLASS_$_Foo
+
+ .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
+ .p2align 3, 0x0
+_OBJC_SELECTOR_REFERENCES_:
+ .quad l_OBJC_METH_VAR_NAME_
+
+ .p2align 3, 0x0
+_OBJC_SELECTOR_REFERENCES_.3:
+ .quad l_OBJC_METH_VAR_NAME_.2
+
+ .section __DATA,__objc_classlist,regular,no_dead_strip
+ .p2align 3, 0x0
+l_OBJC_LABEL_CLASS_$:
+ .quad _OBJC_CLASS_$_Foo
+
+ .section __DATA,__objc_catlist,regular,no_dead_strip
+ .p2align 3, 0x0
+l_OBJC_LABEL_CATEGORY_$:
+ .quad __OBJC_$_CATEGORY_Foo_$_Bar
+
+ .section __DATA,__objc_imageinfo,regular,no_dead_strip
+L_OBJC_IMAGE_INFO:
+ .long 0
+ .long 64
+
+.subsections_via_symbols
ExecutorAddrRange CompactUnwindSection;
};
+ struct ObjCImageInfo {
+ uint32_t Version = 0;
+ uint32_t Flags = 0;
+ ExecutorAddr Addr;
+ };
+
Error bootstrapPipelineStart(jitlink::LinkGraph &G);
Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G);
Error bootstrapPipelineEnd(jitlink::LinkGraph &G);
Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
MaterializationResponsibility &MR);
- Error preserveInitSections(jitlink::LinkGraph &G,
- MaterializationResponsibility &MR);
+ Error preserveImportantSections(jitlink::LinkGraph &G,
+ MaterializationResponsibility &MR);
Error processObjCImageInfo(jitlink::LinkGraph &G,
MaterializationResponsibility &MR);
Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD,
bool InBootstrapPhase);
+ Error createObjCRuntimeObject(jitlink::LinkGraph &G);
+ Error populateObjCRuntimeObject(jitlink::LinkGraph &G,
+ MaterializationResponsibility &MR);
+
std::mutex PluginMutex;
MachOPlatform &MP;
// FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when
// JITDylibs are removed.
- DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos;
+ DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos;
DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
InitSymbolDepMap InitSymbolDeps;
};
ES.intern("___orc_rt_macho_deregister_object_platform_sections")};
RuntimeFunction CreatePThreadKey{
ES.intern("___orc_rt_macho_create_pthread_key")};
+ RuntimeFunction RegisterObjCRuntimeObject{
+ ES.intern("___orc_rt_macho_register_objc_runtime_object")};
+ RuntimeFunction DeregisterObjCRuntimeObject{
+ ES.intern("___orc_rt_macho_deregister_objc_runtime_object")};
DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
namespace orc {
// MachO section names.
+
extern StringRef MachODataCommonSectionName;
extern StringRef MachODataDataSectionName;
extern StringRef MachOEHFrameSectionName;
extern StringRef MachOCompactUnwindInfoSectionName;
extern StringRef MachOModInitFuncSectionName;
+extern StringRef MachOObjCCatListSectionName;
+extern StringRef MachOObjCCatList2SectionName;
extern StringRef MachOObjCClassListSectionName;
+extern StringRef MachOObjCClassNameSectionName;
+extern StringRef MachOObjCClassRefsSectionName;
+extern StringRef MachOObjCConstSectionName;
+extern StringRef MachOObjCDataSectionName;
extern StringRef MachOObjCImageInfoSectionName;
+extern StringRef MachOObjCMethNameSectionName;
+extern StringRef MachOObjCMethTypeSectionName;
+extern StringRef MachOObjCNLCatListSectionName;
extern StringRef MachOObjCSelRefsSectionName;
extern StringRef MachOSwift5ProtoSectionName;
extern StringRef MachOSwift5ProtosSectionName;
extern StringRef MachOSwift5TypesSectionName;
+extern StringRef MachOSwift5TypeRefSectionName;
+extern StringRef MachOSwift5FieldMetadataSectionName;
+extern StringRef MachOSwift5EntrySectionName;
extern StringRef MachOThreadBSSSectionName;
extern StringRef MachOThreadDataSectionName;
extern StringRef MachOThreadVarsSectionName;
-extern StringRef MachOInitSectionNames[6];
+
+extern StringRef MachOInitSectionNames[19];
// ELF section names.
extern StringRef ELFEHFrameSectionName;
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/ExecutionEngine/JITLink/MachO.h"
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
ExecutorAddr MachOHeaderAddr;
};
+static StringRef ObjCRuntimeObjectSectionsData[] = {
+ MachOObjCCatListSectionName, MachOObjCClassListSectionName,
+ MachOObjCClassRefsSectionName, MachOObjCConstSectionName,
+ MachOObjCDataSectionName, MachOObjCSelRefsSectionName};
+
+static StringRef ObjCRuntimeObjectSectionsText[] = {
+ MachOObjCClassNameSectionName, MachOObjCMethNameSectionName,
+ MachOObjCMethTypeSectionName, MachOSwift5TypesSectionName,
+ MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
+ MachOSwift5EntrySectionName, MachOSwift5ProtoSectionName,
+ MachOSwift5ProtosSectionName};
+
+static StringRef ObjCRuntimeObjectSectionName =
+ "__llvm_jitlink_ObjCRuntimeRegistrationObject";
+
} // end anonymous namespace
namespace llvm {
// If the object contains an init symbol other than the header start symbol
// then add passes to preserve, process and register the init
// sections/symbols.
- Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
- if (auto Err = preserveInitSections(G, MR))
+ Config.PrePrunePasses.push_back(
+ [this, &MR](LinkGraph &G) { return preserveImportantSections(G, MR); });
+ Config.PostPrunePasses.push_back(
+ [this](LinkGraph &G) { return createObjCRuntimeObject(G); });
+ Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {
+ if (auto Err = processObjCImageInfo(G, MR))
return Err;
- return processObjCImageInfo(G, MR);
+ return populateObjCRuntimeObject(G, MR);
});
}
&MP.RegisterObjectPlatformSections.Addr},
{*MP.DeregisterObjectPlatformSections.Name,
&MP.DeregisterObjectPlatformSections.Addr},
- {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}};
+ {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr},
+ {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr},
+ {*MP.DeregisterObjCRuntimeObject.Name,
+ &MP.DeregisterObjCRuntimeObject.Addr}};
bool RegisterMachOHeader = false;
return Error::success();
}
-Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
+Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections(
jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
+ // __objc_imageinfo is "important": we want to preserve it and record its
+ // address in the first graph that it appears in, then verify and discard it
+ // in all subsequent graphs. In this pass we preserve unconditionally -- we'll
+ // manually throw it away in the processObjCImageInfo pass.
+ if (auto *ObjCImageInfoSec = G.findSectionByName("__DATA,__objc_imageinfo")) {
+ if (ObjCImageInfoSec->blocks_size() != 1)
+ return make_error<StringError>(
+ "In " + G.getName() +
+ "__DATA,__objc_imageinfo contains multiple blocks",
+ inconvertibleErrorCode());
+ G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false,
+ true);
+ }
+ // Init sections are important: We need to preserve them and so that their
+ // addresses can be captured and reported to the ORC runtime in
+ // registerObjectPlatformSections.
JITLinkSymbolSet InitSectionSymbols;
for (auto &InitSectionName : MachOInitSectionNames) {
// Skip non-init sections.
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)
+ if (ObjCImageInfoItr->second.Version != Version)
return make_error<StringError>(
"ObjC version in " + G.getName() +
" does not match first registered version",
inconvertibleErrorCode());
- if (ObjCImageInfoItr->second.second != Flags)
+ if (ObjCImageInfoItr->second.Flags != Flags)
return make_error<StringError>("ObjC flags in " + G.getName() +
" do not match first registered flags",
inconvertibleErrorCode());
} 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);
+ ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags,
+ ObjCImageInfoBlock.getAddress()};
}
return Error::success();
// If any platform sections were found then add an allocation action to call
// the registration function.
- StringRef PlatformSections[] = {
- MachOModInitFuncSectionName, MachOObjCClassListSectionName,
- MachOObjCSelRefsSectionName, MachOSwift5ProtoSectionName,
- MachOSwift5ProtosSectionName, MachOSwift5TypesSectionName,
- };
+ StringRef PlatformSections[] = {MachOModInitFuncSectionName,
+ ObjCRuntimeObjectSectionName};
for (auto &SecName : PlatformSections) {
auto *Sec = G.findSectionByName(SecName);
return Error::success();
}
+Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
+ jitlink::LinkGraph &G) {
+
+ bool NeedTextSegment = false;
+ size_t NumRuntimeSections = 0;
+
+ for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)
+ if (auto *Sec = G.findSectionByName(ObjCRuntimeSectionName))
+ ++NumRuntimeSections;
+
+ for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
+ if (auto *Sec = G.findSectionByName(ObjCRuntimeSectionName)) {
+ ++NumRuntimeSections;
+ NeedTextSegment = true;
+ }
+ }
+
+ // Early out for no runtime sections.
+ if (NumRuntimeSections == 0)
+ return Error::success();
+
+ // If there were any runtime sections then we need to add an __objc_imageinfo
+ // section.
+ ++NumRuntimeSections;
+
+ size_t MachOSize = sizeof(MachO::mach_header_64) +
+ (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +
+ NumRuntimeSections * sizeof(MachO::section_64);
+
+ auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,
+ MemProt::Read | MemProt::Write);
+ G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);
+
+ return Error::success();
+}
+
+Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
+ jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
+
+ auto *ObjCRuntimeObjectSec =
+ G.findSectionByName(ObjCRuntimeObjectSectionName);
+
+ if (!ObjCRuntimeObjectSec)
+ return Error::success();
+
+ auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();
+
+ std::vector<MachO::section_64> TextSections, DataSections;
+ auto AddSection = [&](MachO::section_64 &Sec, jitlink::Section &GraphSec) {
+ jitlink::SectionRange SR(GraphSec);
+ StringRef FQName = GraphSec.getName();
+ memset(&Sec, 0, sizeof(MachO::section_64));
+ memcpy(Sec.sectname, FQName.drop_front(7).data(), FQName.size() - 7);
+ memcpy(Sec.segname, FQName.data(), 6);
+ Sec.addr = SR.getStart() - SecBlock.getAddress();
+ Sec.size = SR.getSize();
+ Sec.flags = MachO::S_REGULAR;
+ };
+
+ // Add the __objc_imageinfo section.
+ {
+ DataSections.push_back({});
+ auto &Sec = DataSections.back();
+ memset(&Sec, 0, sizeof(Sec));
+ strcpy(Sec.sectname, "__objc_imageinfo");
+ strcpy(Sec.segname, "__DATA");
+ std::lock_guard<std::mutex> Lock(PluginMutex);
+ auto I = ObjCImageInfos.find(&MR.getTargetJITDylib());
+ assert(I != ObjCImageInfos.end() && "Missing __objc_imageinfo");
+ assert(std::get<2>(I->second) && "Null __objc_imageinfo");
+ Sec.addr = I->second.Addr - SecBlock.getAddress();
+ Sec.size = 8;
+ }
+
+ for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {
+ if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
+ DataSections.push_back({});
+ AddSection(DataSections.back(), *GraphSec);
+ }
+ }
+
+ for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
+ if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
+ TextSections.push_back({});
+ AddSection(TextSections.back(), *GraphSec);
+ }
+ }
+
+ MachO::mach_header_64 Hdr;
+ Hdr.magic = MachO::MH_MAGIC_64;
+ switch (G.getTargetTriple().getArch()) {
+ case Triple::aarch64:
+ Hdr.cputype = MachO::CPU_TYPE_ARM64;
+ Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
+ break;
+ case Triple::x86_64:
+ Hdr.cputype = MachO::CPU_TYPE_X86_64;
+ Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
+ break;
+ default:
+ return make_error<StringError>("Unrecognized MachO arch in triple " +
+ G.getTargetTriple().str(),
+ inconvertibleErrorCode());
+ }
+
+ Hdr.filetype = MachO::MH_DYLIB;
+ Hdr.ncmds = 1 + !TextSections.empty();
+ Hdr.sizeofcmds =
+ Hdr.ncmds * sizeof(MachO::segment_command_64) +
+ (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64);
+ Hdr.flags = 0;
+ Hdr.reserved = 0;
+
+ assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&
+ "Unexpected number of blocks in runtime sections object");
+ auto SecContent = SecBlock.getAlreadyMutableContent();
+
+ char *P = SecContent.data();
+ auto WriteMachOStruct = [&](auto S) {
+ if (G.getEndianness() != support::endian::system_endianness())
+ MachO::swapStruct(S);
+ memcpy(P, &S, sizeof(S));
+ P += sizeof(S);
+ };
+
+ auto WriteSegment = [&](StringRef Name,
+ const std::vector<MachO::section_64> &Secs) {
+ MachO::segment_command_64 SegLC;
+ memset(&SegLC, 0, sizeof(SegLC));
+ memcpy(SegLC.segname, Name.data(), Name.size());
+ SegLC.cmd = MachO::LC_SEGMENT_64;
+ SegLC.cmdsize = sizeof(MachO::segment_command_64) +
+ Secs.size() * sizeof(MachO::section_64);
+ SegLC.nsects = Secs.size();
+ WriteMachOStruct(SegLC);
+ for (auto &Sec : Secs)
+ WriteMachOStruct(Sec);
+ };
+
+ WriteMachOStruct(Hdr);
+ if (!TextSections.empty())
+ WriteSegment("__TEXT", TextSections);
+ if (!DataSections.empty())
+ WriteSegment("__DATA", DataSections);
+
+ assert(P == SecContent.end() && "Underflow writing ObjC runtime object");
+ return Error::success();
+}
+
} // End namespace orc.
} // End namespace llvm.
StringRef MachOEHFrameSectionName = "__TEXT,__eh_frame";
StringRef MachOCompactUnwindInfoSectionName = "__TEXT,__unwind_info";
StringRef MachOModInitFuncSectionName = "__DATA,__mod_init_func";
+StringRef MachOObjCCatListSectionName = "__DATA,__objc_catlist";
+StringRef MachOObjCCatList2SectionName = "__DATA,__objc_catlist2";
StringRef MachOObjCClassListSectionName = "__DATA,__objc_classlist";
+StringRef MachOObjCClassNameSectionName = "__TEXT,__objc_classname";
+StringRef MachOObjCClassRefsSectionName = "__DATA,__objc_classrefs";
+StringRef MachOObjCConstSectionName = "__DATA,__objc_const";
+StringRef MachOObjCDataSectionName = "__DATA,__objc_data";
StringRef MachOObjCImageInfoSectionName = "__DATA,__objc_imageinfo";
+StringRef MachOObjCMethNameSectionName = "__TEXT,__objc_methname";
+StringRef MachOObjCMethTypeSectionName = "__TEXT,__objc_methtype";
+StringRef MachOObjCNLCatListSectionName = "__DATA,__objc_nlcatlist";
StringRef MachOObjCSelRefsSectionName = "__DATA,__objc_selrefs";
StringRef MachOSwift5ProtoSectionName = "__TEXT,__swift5_proto";
StringRef MachOSwift5ProtosSectionName = "__TEXT,__swift5_protos";
StringRef MachOSwift5TypesSectionName = "__TEXT,__swift5_types";
+StringRef MachOSwift5TypeRefSectionName = "__TEXT,__swift5_typeref";
+StringRef MachOSwift5FieldMetadataSectionName = "__TEXT,__swift5_fieldmd";
+StringRef MachOSwift5EntrySectionName = "__TEXT,__swift5_entry";
StringRef MachOThreadBSSSectionName = "__DATA,__thread_bss";
StringRef MachOThreadDataSectionName = "__DATA,__thread_data";
StringRef MachOThreadVarsSectionName = "__DATA,__thread_vars";
-StringRef MachOInitSectionNames[6] = {
- MachOModInitFuncSectionName, MachOObjCSelRefsSectionName,
- MachOObjCClassListSectionName, MachOSwift5ProtosSectionName,
- MachOSwift5ProtoSectionName, MachOSwift5TypesSectionName};
+StringRef MachOInitSectionNames[19] = {
+ MachOModInitFuncSectionName, MachOObjCCatListSectionName,
+ MachOObjCCatList2SectionName, MachOObjCClassListSectionName,
+ MachOObjCClassNameSectionName, MachOObjCClassRefsSectionName,
+ MachOObjCConstSectionName, MachOObjCDataSectionName,
+ MachOObjCImageInfoSectionName, MachOObjCMethNameSectionName,
+ MachOObjCMethTypeSectionName, MachOObjCNLCatListSectionName,
+ MachOObjCSelRefsSectionName, MachOSwift5ProtoSectionName,
+ MachOSwift5ProtosSectionName, MachOSwift5TypesSectionName,
+ MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
+ MachOSwift5EntrySectionName,
+};
StringRef ELFEHFrameSectionName = ".eh_frame";
StringRef ELFInitArrayFuncSectionName = ".init_array";