set(ORC_SOURCES
extensible_rtti.cpp
log_error_to_stderr.cpp
+ macho_ehframe_registration.cpp
macho_platform.cpp
elfnix_platform.cpp
run_program_wrapper.cpp
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_get_deinitializers_tag)
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag)
-// eh-frame registration functions.
-// We expect these to be available for all processes.
-extern "C" void __register_frame(const void *);
-extern "C" void __deregister_frame(const void *);
-
// Objective-C types.
struct objc_class;
struct objc_image_info;
namespace {
-template <typename HandleFDEFn>
-void walkEHFrameSection(span<const char> EHFrameSection,
- HandleFDEFn HandleFDE) {
- const char *CurCFIRecord = EHFrameSection.data();
- uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
-
- while (CurCFIRecord != EHFrameSection.end() && Size != 0) {
- const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
- if (Size == 0xffffffff)
- Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
- else
- Size += 4;
- uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
-
- if (Offset != 0)
- HandleFDE(CurCFIRecord);
-
- CurCFIRecord += Size;
- Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
- }
-}
-
Error validatePointerSectionExtent(const char *SectionName,
const ExecutorAddrRange &SE) {
if (SE.size().getValue() % sizeof(uintptr_t)) {
MachOPlatformRuntimeState(MachOPlatformRuntimeState &&) = delete;
MachOPlatformRuntimeState &operator=(MachOPlatformRuntimeState &&) = delete;
- Error registerObjectSections(MachOPerObjectSectionsToRegister POSR);
- Error deregisterObjectSections(MachOPerObjectSectionsToRegister POSR);
+ Error registerThreadDataSection(span<const char> ThreadDataSec);
+ Error deregisterThreadDataSection(span<const char> ThreadDataSec);
const char *dlerror();
void *dlopen(string_view Name, int Mode);
PerJITDylibState *getJITDylibStateByName(string_view Path);
PerJITDylibState &getOrCreateJITDylibState(MachOJITDylibInitializers &MOJDIs);
- Error registerThreadDataSection(span<const char> ThreadDataSec);
-
Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle,
string_view Symbol);
delete MOPS;
}
-Error MachOPlatformRuntimeState::registerObjectSections(
- MachOPerObjectSectionsToRegister POSR) {
- if (POSR.EHFrameSection.Start)
- walkEHFrameSection(POSR.EHFrameSection.toSpan<const char>(),
- __register_frame);
-
- if (POSR.ThreadDataSection.Start) {
- if (auto Err = registerThreadDataSection(
- POSR.ThreadDataSection.toSpan<const char>()))
- return Err;
+Error MachOPlatformRuntimeState::registerThreadDataSection(
+ span<const char> ThreadDataSection) {
+ std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
+ auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
+ if (I != ThreadDataSections.begin()) {
+ auto J = std::prev(I);
+ if (J->first + J->second > ThreadDataSection.data())
+ return make_error<StringError>("Overlapping __thread_data sections");
}
-
+ ThreadDataSections.insert(
+ I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
return Error::success();
}
-Error MachOPlatformRuntimeState::deregisterObjectSections(
- MachOPerObjectSectionsToRegister POSR) {
- if (POSR.EHFrameSection.Start)
- walkEHFrameSection(POSR.EHFrameSection.toSpan<const char>(),
- __deregister_frame);
-
+Error MachOPlatformRuntimeState::deregisterThreadDataSection(
+ span<const char> ThreadDataSection) {
+ std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
+ auto I = ThreadDataSections.find(ThreadDataSection.end());
+ if (I == ThreadDataSections.end())
+ return make_error<StringError>("Attempt to deregister unknown thread data "
+ "section");
+ ThreadDataSections.erase(I);
return Error::success();
}
return JDS;
}
-Error MachOPlatformRuntimeState::registerThreadDataSection(
- span<const char> ThreadDataSection) {
- std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
- auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
- if (I != ThreadDataSections.begin()) {
- auto J = std::prev(I);
- if (J->first + J->second > ThreadDataSection.data())
- return make_error<StringError>("Overlapping __thread_data sections");
- }
- ThreadDataSections.insert(
- I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
- return Error::success();
-}
-
Expected<ExecutorAddr>
MachOPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle,
string_view Sym) {
delete static_cast<MachOPlatformRuntimeTLVManager *>(MachOTLVMgr);
}
+Error runWrapperFunctionCalls(std::vector<WrapperFunctionCall> WFCs) {
+ for (auto &WFC : WFCs)
+ if (auto Err = WFC.runWithSPSRet())
+ return Err;
+ return Error::success();
+}
+
} // end anonymous namespace
//------------------------------------------------------------------------------
return WrapperFunctionResult().release();
}
-/// Wrapper function for registering metadata on a per-object basis.
ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
-__orc_rt_macho_register_object_sections(char *ArgData, size_t ArgSize) {
- return WrapperFunction<SPSError(SPSMachOPerObjectSectionsToRegister)>::handle(
- ArgData, ArgSize,
- [](MachOPerObjectSectionsToRegister &POSR) {
- return MachOPlatformRuntimeState::get().registerObjectSections(
- std::move(POSR));
+__orc_rt_macho_register_thread_data_section(char *ArgData, size_t ArgSize) {
+ // NOTE: Does not use SPS to deserialize arg buffer, instead the arg buffer
+ // is taken to be the range of the thread data section.
+ return WrapperFunction<SPSError()>::handle(
+ nullptr, 0,
+ [&]() {
+ return MachOPlatformRuntimeState::get()
+ .registerThreadDataSection(
+ span<const char>(ArgData, ArgSize));
})
.release();
}
-/// Wrapper for releasing per-object metadat.
ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
-__orc_rt_macho_deregister_object_sections(char *ArgData, size_t ArgSize) {
- return WrapperFunction<SPSError(SPSMachOPerObjectSectionsToRegister)>::handle(
- ArgData, ArgSize,
- [](MachOPerObjectSectionsToRegister &POSR) {
- return MachOPlatformRuntimeState::get().deregisterObjectSections(
- std::move(POSR));
+__orc_rt_macho_deregister_thread_data_section(char *ArgData, size_t ArgSize) {
+ // NOTE: Does not use SPS to deserialize arg buffer, instead the arg buffer
+ // is taken to be the range of the thread data section.
+ return WrapperFunction<SPSError()>::handle(
+ nullptr, 0,
+ [&]() {
+ return MachOPlatformRuntimeState::get()
+ .deregisterThreadDataSection(
+ span<const char>(ArgData, ArgSize));
})
.release();
}
+ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
+__orc_rt_macho_run_wrapper_function_calls(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSSequence<SPSWrapperFunctionCall>)>::handle(
+ ArgData, ArgSize, runWrapperFunctionCalls)
+ .release();
+}
+
//------------------------------------------------------------------------------
// TLV support
//------------------------------------------------------------------------------
namespace __orc_rt {
namespace macho {
-struct MachOPerObjectSectionsToRegister {
- ExecutorAddrRange EHFrameSection;
- ExecutorAddrRange ThreadDataSection;
-};
-
struct MachOJITDylibInitializers {
using SectionList = std::vector<ExecutorAddrRange>;
} // end namespace macho
-using SPSMachOPerObjectSectionsToRegister =
- SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
-
-template <>
-class SPSSerializationTraits<SPSMachOPerObjectSectionsToRegister,
- macho::MachOPerObjectSectionsToRegister> {
-
-public:
- static size_t size(const macho::MachOPerObjectSectionsToRegister &MOPOSR) {
- return SPSMachOPerObjectSectionsToRegister::AsArgList::size(
- MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
- }
-
- static bool serialize(SPSOutputBuffer &OB,
- const macho::MachOPerObjectSectionsToRegister &MOPOSR) {
- return SPSMachOPerObjectSectionsToRegister::AsArgList::serialize(
- OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
- }
-
- static bool deserialize(SPSInputBuffer &IB,
- macho::MachOPerObjectSectionsToRegister &MOPOSR) {
- return SPSMachOPerObjectSectionsToRegister::AsArgList::deserialize(
- IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
- }
-};
-
using SPSNamedExecutorAddrRangeSequenceMap =
SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRangeSequence>>;
namespace llvm {
namespace orc {
-struct MachOPerObjectSectionsToRegister {
- ExecutorAddrRange EHFrameSection;
- ExecutorAddrRange ThreadDataSection;
-};
-
struct MachOJITDylibInitializers {
using SectionList = std::vector<ExecutorAddrRange>;
Error registerEHAndTLVSections(jitlink::LinkGraph &G);
+ Error registerEHSectionsPhase1(jitlink::LinkGraph &G);
+
std::mutex PluginMutex;
MachOPlatform &MP;
DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos;
Error registerInitInfo(JITDylib &JD, ExecutorAddr ObjCImageInfoAddr,
ArrayRef<jitlink::Section *> InitSections);
- Error registerPerObjectSections(const MachOPerObjectSectionsToRegister &POSR);
-
Expected<uint64_t> createPThreadKey();
+ enum PlatformState { BootstrapPhase1, BootstrapPhase2, Initialized };
+
ExecutionSession &ES;
ObjectLinkingLayer &ObjLinkingLayer;
SymbolStringPtr MachOHeaderStartSymbol;
- std::atomic<bool> RuntimeBootstrapped{false};
+ std::atomic<PlatformState> State{BootstrapPhase1};
ExecutorAddr orc_rt_macho_platform_bootstrap;
ExecutorAddr orc_rt_macho_platform_shutdown;
- ExecutorAddr orc_rt_macho_register_object_sections;
+ ExecutorAddr orc_rt_macho_register_ehframe_section;
+ ExecutorAddr orc_rt_macho_deregister_ehframe_section;
+ ExecutorAddr orc_rt_macho_register_thread_data_section;
+ ExecutorAddr orc_rt_macho_deregister_thread_data_section;
ExecutorAddr orc_rt_macho_create_pthread_key;
DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
// aggregating data from the jitlink.
std::mutex PlatformMutex;
DenseMap<JITDylib *, MachOJITDylibInitializers> InitSeqs;
- std::vector<MachOPerObjectSectionsToRegister> BootstrapPOSRs;
DenseMap<JITTargetAddress, JITDylib *> HeaderAddrToJITDylib;
DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
namespace shared {
-using SPSMachOPerObjectSectionsToRegister =
- SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
-
-template <>
-class SPSSerializationTraits<SPSMachOPerObjectSectionsToRegister,
- MachOPerObjectSectionsToRegister> {
-
-public:
- static size_t size(const MachOPerObjectSectionsToRegister &MOPOSR) {
- return SPSMachOPerObjectSectionsToRegister::AsArgList::size(
- MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
- }
-
- static bool serialize(SPSOutputBuffer &OB,
- const MachOPerObjectSectionsToRegister &MOPOSR) {
- return SPSMachOPerObjectSectionsToRegister::AsArgList::serialize(
- OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
- }
-
- static bool deserialize(SPSInputBuffer &IB,
- MachOPerObjectSectionsToRegister &MOPOSR) {
- return SPSMachOPerObjectSectionsToRegister::AsArgList::deserialize(
- IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
- }
-};
-
using SPSNamedExecutorAddrRangeSequenceMap =
SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRangeSequence>>;
PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
+ // Force linking of eh-frame registration functions.
+ if (auto Err2 = lookupAndRecordAddrs(
+ ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
+ {{ES.intern("___orc_rt_macho_register_ehframe_section"),
+ &orc_rt_macho_register_ehframe_section},
+ {ES.intern("___orc_rt_macho_deregister_ehframe_section"),
+ &orc_rt_macho_deregister_ehframe_section}})) {
+ Err = std::move(Err2);
+ return;
+ }
+
+ State = BootstrapPhase2;
+
// PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
// the platform now), so set it up.
if (auto E2 = setupJITDylib(PlatformJD)) {
Err = std::move(E2);
return;
}
+
+ State = Initialized;
}
Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
}
Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) {
-
if (auto Err = lookupAndRecordAddrs(
ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
{{ES.intern("___orc_rt_macho_platform_bootstrap"),
&orc_rt_macho_platform_bootstrap},
{ES.intern("___orc_rt_macho_platform_shutdown"),
&orc_rt_macho_platform_shutdown},
- {ES.intern("___orc_rt_macho_register_object_sections"),
- &orc_rt_macho_register_object_sections},
+ {ES.intern("___orc_rt_macho_register_thread_data_section"),
+ &orc_rt_macho_register_thread_data_section},
+ {ES.intern("___orc_rt_macho_deregister_thread_data_section"),
+ &orc_rt_macho_deregister_thread_data_section},
{ES.intern("___orc_rt_macho_create_pthread_key"),
&orc_rt_macho_create_pthread_key}}))
return Err;
- if (auto Err = ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap))
- return Err;
-
- // FIXME: Ordering is fuzzy here. We're probably best off saying
- // "behavior is undefined if code that uses the runtime is added before
- // the platform constructor returns", then move all this to the constructor.
- RuntimeBootstrapped = true;
- std::vector<MachOPerObjectSectionsToRegister> DeferredPOSRs;
- {
- std::lock_guard<std::mutex> Lock(PlatformMutex);
- DeferredPOSRs = std::move(BootstrapPOSRs);
- }
-
- for (auto &D : DeferredPOSRs)
- if (auto Err = registerPerObjectSections(D))
- return Err;
-
- return Error::success();
+ return ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap);
}
Error MachOPlatform::registerInitInfo(
return Error::success();
}
-Error MachOPlatform::registerPerObjectSections(
- const MachOPerObjectSectionsToRegister &POSR) {
-
- if (!orc_rt_macho_register_object_sections)
- return make_error<StringError>("Attempting to register per-object "
- "sections, but runtime support has not "
- "been loaded yet",
- inconvertibleErrorCode());
-
- Error ErrResult = Error::success();
- if (auto Err = ES.callSPSWrapper<shared::SPSError(
- SPSMachOPerObjectSectionsToRegister)>(
- orc_rt_macho_register_object_sections, ErrResult, POSR))
- return Err;
- return ErrResult;
-}
-
Expected<uint64_t> MachOPlatform::createPThreadKey() {
if (!orc_rt_macho_create_pthread_key)
return make_error<StringError>(
MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
jitlink::PassConfiguration &Config) {
+ auto PS = MP.State.load();
+
// --- Handle Initializers ---
if (auto InitSymbol = MR.getInitializerSymbol()) {
}
// --- Add passes for eh-frame and TLV support ---
+ if (PS == MachOPlatform::BootstrapPhase1) {
+ Config.PostFixupPasses.push_back(
+ [this](jitlink::LinkGraph &G) { return registerEHSectionsPhase1(G); });
+ return;
+ }
// Insert TLV lowering at the start of the PostPrunePasses, since we want
// it to run before GOT/PLT lowering.
Error MachOPlatform::MachOPlatformPlugin::registerEHAndTLVSections(
jitlink::LinkGraph &G) {
- MachOPerObjectSectionsToRegister POSR;
+ // Add a pass to register the final addresses of the eh-frame and TLV sections
+ // with the runtime.
if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) {
jitlink::SectionRange R(*EHFrameSection);
if (!R.empty())
- POSR.EHFrameSection = {ExecutorAddr(R.getStart()),
- ExecutorAddr(R.getEnd())};
+ G.allocActions().push_back(
+ {{MP.orc_rt_macho_register_ehframe_section.getValue(), R.getStart(),
+ R.getSize()},
+ {MP.orc_rt_macho_deregister_ehframe_section.getValue(), R.getStart(),
+ R.getSize()}});
}
// Get a pointer to the thread data section if there is one. It will be used
// record the resulting section range.
if (ThreadDataSection) {
jitlink::SectionRange R(*ThreadDataSection);
- if (!R.empty())
- POSR.ThreadDataSection = {ExecutorAddr(R.getStart()),
- ExecutorAddr(R.getEnd())};
+ if (!R.empty()) {
+ if (MP.State != MachOPlatform::Initialized)
+ return make_error<StringError>("__thread_data section encountered, but "
+ "MachOPlatform has not finished booting",
+ inconvertibleErrorCode());
+
+ G.allocActions().push_back(
+ {{MP.orc_rt_macho_register_thread_data_section.getValue(),
+ R.getStart(), R.getSize()},
+ {MP.orc_rt_macho_deregister_thread_data_section.getValue(),
+ R.getStart(), R.getSize()}});
+ }
}
+ return Error::success();
+}
+
+Error MachOPlatform::MachOPlatformPlugin::registerEHSectionsPhase1(
+ jitlink::LinkGraph &G) {
- if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {
+ // If there's no eh-frame there's nothing to do.
+ auto *EHFrameSection = G.findSectionByName(EHFrameSectionName);
+ if (!EHFrameSection)
+ return Error::success();
- // If we're still bootstrapping the runtime then just record this
- // frame for now.
- if (!MP.RuntimeBootstrapped) {
- std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
- MP.BootstrapPOSRs.push_back(POSR);
- return Error::success();
- }
+ // If the eh-frame section is empty there's nothing to do.
+ jitlink::SectionRange R(*EHFrameSection);
+ if (R.empty())
+ return Error::success();
- // Otherwise register it immediately.
- if (auto Err = MP.registerPerObjectSections(POSR))
- return Err;
+ // Since we're linking the object containing the registration code now the
+ // addresses won't be ready in the platform. We'll have to find them in this
+ // graph instead.
+ ExecutorAddr orc_rt_macho_register_ehframe_section;
+ ExecutorAddr orc_rt_macho_deregister_ehframe_section;
+ for (auto *Sym : G.defined_symbols()) {
+ if (!Sym->hasName())
+ continue;
+ if (Sym->getName() == "___orc_rt_macho_register_ehframe_section")
+ orc_rt_macho_register_ehframe_section = ExecutorAddr(Sym->getAddress());
+ else if (Sym->getName() == "___orc_rt_macho_deregister_ehframe_section")
+ orc_rt_macho_deregister_ehframe_section = ExecutorAddr(Sym->getAddress());
+
+ if (orc_rt_macho_register_ehframe_section &&
+ orc_rt_macho_deregister_ehframe_section)
+ break;
}
+ // If we failed to find the required functions then bail out.
+ if (!orc_rt_macho_register_ehframe_section ||
+ !orc_rt_macho_deregister_ehframe_section)
+ return make_error<StringError>("Could not find eh-frame registration "
+ "functions during platform bootstrap",
+ inconvertibleErrorCode());
+
+ // Otherwise, add allocation actions to the graph to register eh-frames for
+ // this object.
+ G.allocActions().push_back(
+ {{orc_rt_macho_register_ehframe_section.getValue(), R.getStart(),
+ R.getSize()},
+ {orc_rt_macho_deregister_ehframe_section.getValue(), R.getStart(),
+ R.getSize()}});
+
return Error::success();
}