[ORC][ORC-RT][MachO] Use _objc_(map|load)_images for ObjC & Swift registration.

This patch drops the individual registration calls to the ObjC and Swift
runtimes (for selectors, classes, etc.), and instead creates a Mach header and
load commands that can be passed to _objc_map_images and _objc_load_images to
trigger registration and execution of +load methods. This approach supports
categories (for which there is no current registration API), and more closely
follows dyld's ObjC & Swift registration path.
This commit is contained in:
Lang Hames
2023-04-07 14:40:05 -07:00
parent af6ad7ac9a
commit f448d44663
6 changed files with 470 additions and 193 deletions

View File

@@ -36,40 +36,18 @@ using namespace __orc_rt::macho;
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 {
@@ -290,11 +268,7 @@ private:
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;
@@ -357,11 +331,7 @@ private:
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);
@@ -580,22 +550,12 @@ Error MachOPlatformRuntimeState::registerObjectPlatformSections(
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 {
@@ -675,16 +635,8 @@ Error MachOPlatformRuntimeState::deregisterObjectPlatformSections(
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 {
@@ -905,115 +857,24 @@ Error MachOPlatformRuntimeState::deregisterEHFrames(
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");
"Could not register Objective-C / Swift metadata: _objc_map_images / "
"_objc_load_image not found");
JDS.Swift5ProtocolConformancesSections.processNewSections(
[](span<char> ProtoConfSec) {
swift_registerProtocolConformances(
reinterpret_cast<const ProtocolConformanceRecord *>(
ProtoConfSec.data()),
reinterpret_cast<const ProtocolConformanceRecord *>(
ProtoConfSec.data() + ProtoConfSec.size()));
});
std::vector<char *> RegObjBases;
JDS.ObjCRuntimeRegistrationObjects.processNewSections(
[&](span<char> RegObj) { RegObjBases.push_back(RegObj.data()); });
return Error::success();
}
std::vector<char *> Paths;
Paths.resize(RegObjBases.size());
_objc_map_images(RegObjBases.size(), Paths.data(),
reinterpret_cast<mach_header **>(RegObjBases.data()));
Error MachOPlatformRuntimeState::registerSwift5Types(JITDylibState &JDS) {
if (!JDS.Swift5TypesSections.hasNewSections())
return Error::success();
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();
}
@@ -1151,15 +1012,7 @@ Error MachOPlatformRuntimeState::dlopenInitialize(
}
// 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;

View File

@@ -0,0 +1,190 @@
// 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

View File

@@ -156,6 +156,12 @@ private:
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);
@@ -165,8 +171,8 @@ private:
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);
@@ -178,12 +184,16 @@ private:
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;
};
@@ -253,6 +263,10 @@ private:
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;

View File

@@ -19,21 +19,35 @@ namespace llvm {
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;

View File

@@ -9,6 +9,7 @@
#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"
@@ -246,6 +247,21 @@ private:
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 {
@@ -742,10 +758,14 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
// 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);
});
}
@@ -806,7 +826,10 @@ Error MachOPlatform::MachOPlatformPlugin::
&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;
@@ -875,9 +898,25 @@ Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
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.
@@ -967,12 +1006,12 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
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());
@@ -984,7 +1023,8 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
} 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();
@@ -1165,11 +1205,8 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
// 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);
@@ -1230,5 +1267,154 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
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.

View File

@@ -20,20 +20,40 @@ StringRef MachODataDataSectionName = "__DATA,__data";
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";