Skip to content

[ORC][Runtime] Add dlupdate for MachO #97441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 11, 2024
13 changes: 13 additions & 0 deletions compiler-rt/lib/orc/dlfcn_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ using namespace orc_rt;

extern "C" const char *__orc_rt_jit_dlerror();
extern "C" void *__orc_rt_jit_dlopen(const char *path, int mode);
extern "C" int __orc_rt_jit_dlupdate(void *dso_handle, int mode);
extern "C" int __orc_rt_jit_dlclose(void *dso_handle);

ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
Expand All @@ -41,6 +42,18 @@ __orc_rt_jit_dlopen_wrapper(const char *ArgData, size_t ArgSize) {
.release();
}

#ifdef __APPLE__
ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_jit_dlupdate_wrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::handle(
ArgData, ArgSize,
[](ExecutorAddr &DSOHandle, int32_t mode) {
return __orc_rt_jit_dlupdate(DSOHandle.toPtr<void *>(), mode);
})
.release();
}
#endif

ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_jit_dlclose_wrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<int32_t(SPSExecutorAddr)>::handle(
Expand Down
86 changes: 86 additions & 0 deletions compiler-rt/lib/orc/macho_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ class MachOPlatformRuntimeState {

const char *dlerror();
void *dlopen(std::string_view Name, int Mode);
int dlupdate(void *DSOHandle, int Mode);
int dlclose(void *DSOHandle);
void *dlsym(void *DSOHandle, const char *Symbol);

Expand Down Expand Up @@ -380,6 +381,12 @@ class MachOPlatformRuntimeState {
Error dlopenInitialize(std::unique_lock<std::mutex> &JDStatesLock,
JITDylibState &JDS, MachOJITDylibDepInfoMap &DepInfo);

Error dlupdateImpl(void *DSOHandle, int Mode);
Error dlupdateFull(std::unique_lock<std::mutex> &JDStatesLock,
JITDylibState &JDS);
Error dlupdateInitialize(std::unique_lock<std::mutex> &JDStatesLock,
JITDylibState &JDS);

Error dlcloseImpl(void *DSOHandle);
Error dlcloseDeinitialize(std::unique_lock<std::mutex> &JDStatesLock,
JITDylibState &JDS);
Expand Down Expand Up @@ -789,6 +796,20 @@ void *MachOPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
}
}

int MachOPlatformRuntimeState::dlupdate(void *DSOHandle, int Mode) {
ORC_RT_DEBUG({
std::string S;
printdbg("MachOPlatform::dlupdate(%p) (%s)\n", DSOHandle, S.c_str());
});
std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
if (auto Err = dlupdateImpl(DSOHandle, Mode)) {
// FIXME: Make dlerror thread safe.
DLFcnError = toString(std::move(Err));
return -1;
}
return 0;
}

int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
ORC_RT_DEBUG({
auto *JDS = getJITDylibStateByHeader(DSOHandle);
Expand Down Expand Up @@ -1244,6 +1265,67 @@ Error MachOPlatformRuntimeState::dlopenInitialize(
return Error::success();
}

Error MachOPlatformRuntimeState::dlupdateImpl(void *DSOHandle, int Mode) {
std::unique_lock<std::mutex> Lock(JDStatesMutex);

// Try to find JITDylib state by DSOHandle.
auto *JDS = getJITDylibStateByHeader(DSOHandle);

if (!JDS) {
std::ostringstream ErrStream;
ErrStream << "No registered JITDylib for " << DSOHandle;
return make_error<StringError>(ErrStream.str());
}

if (!JDS->referenced())
return make_error<StringError>("dlupdate failed, JITDylib must be open.");

if (!JDS->Sealed) {
if (auto Err = dlupdateFull(Lock, *JDS))
return Err;
}

return Error::success();
}

Error MachOPlatformRuntimeState::dlupdateFull(
std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
// Call back to the JIT to push the initializers.
Expected<MachOJITDylibDepInfoMap> DepInfo((MachOJITDylibDepInfoMap()));
// Unlock so that we can accept the initializer update.
JDStatesLock.unlock();
if (auto Err = WrapperFunction<SPSExpected<SPSMachOJITDylibDepInfoMap>(
SPSExecutorAddr)>::
call(JITDispatch(&__orc_rt_macho_push_initializers_tag), DepInfo,
ExecutorAddr::fromPtr(JDS.Header)))
return Err;
JDStatesLock.lock();

if (!DepInfo)
return DepInfo.takeError();

if (auto Err = dlupdateInitialize(JDStatesLock, JDS))
return Err;

return Error::success();
}

Error MachOPlatformRuntimeState::dlupdateInitialize(
std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
ORC_RT_DEBUG({
printdbg("MachOPlatformRuntimeState::dlupdateInitialize(\"%s\")\n",
JDS.Name.c_str());
});

// Initialize this JITDylib.
if (auto Err = registerObjCRegistrationObjects(JDStatesLock, JDS))
return Err;
if (auto Err = runModInits(JDStatesLock, JDS))
return Err;

return Error::success();
}

Error MachOPlatformRuntimeState::dlcloseImpl(void *DSOHandle) {
std::unique_lock<std::mutex> Lock(JDStatesMutex);

Expand Down Expand Up @@ -1517,6 +1599,10 @@ void *__orc_rt_macho_jit_dlopen(const char *path, int mode) {
return MachOPlatformRuntimeState::get().dlopen(path, mode);
}

int __orc_rt_macho_jit_dlupdate(void *dso_handle, int mode) {
return MachOPlatformRuntimeState::get().dlupdate(dso_handle, mode);
}

int __orc_rt_macho_jit_dlclose(void *dso_handle) {
return MachOPlatformRuntimeState::get().dlclose(dso_handle);
}
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/orc/macho_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ ORC_RT_INTERFACE void __orc_rt_macho_cxa_finalize(void *dso_handle);
// dlfcn functions.
ORC_RT_INTERFACE const char *__orc_rt_macho_jit_dlerror();
ORC_RT_INTERFACE void *__orc_rt_macho_jit_dlopen(const char *path, int mode);
ORC_RT_INTERFACE int __orc_rt_macho_jit_dlupdate(void *dso_handle, int mode);
ORC_RT_INTERFACE int __orc_rt_macho_jit_dlclose(void *dso_handle);
ORC_RT_INTERFACE void *__orc_rt_macho_jit_dlsym(void *dso_handle,
const char *symbol);
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_LLJIT_H
#define LLVM_EXECUTIONENGINE_ORC_LLJIT_H

#include "llvm/ADT/SmallSet.h"
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
Expand Down Expand Up @@ -620,6 +621,7 @@ class ORCPlatformSupport : public LLJIT::PlatformSupport {
private:
orc::LLJIT &J;
DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
SmallPtrSet<JITDylib const *, 8> InitializedDylib;
};

} // End namespace orc
Expand Down
27 changes: 25 additions & 2 deletions llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ Error ORCPlatformSupport::initialize(orc::JITDylib &JD) {
using llvm::orc::shared::SPSExecutorAddr;
using llvm::orc::shared::SPSString;
using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
using SPSDLUpdateSig = int32_t(SPSExecutorAddr, int32_t);
enum dlopen_mode : int32_t {
ORC_RT_RTLD_LAZY = 0x1,
ORC_RT_RTLD_NOW = 0x2,
Expand All @@ -612,9 +613,30 @@ Error ORCPlatformSupport::initialize(orc::JITDylib &JD) {
auto &ES = J.getExecutionSession();
auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
[](const JITDylibSearchOrder &SO) { return SO; });
StringRef WrapperToCall = "__orc_rt_jit_dlopen_wrapper";
bool dlupdate = false;
if (ES.getTargetTriple().isOSBinFormatMachO()) {
if (InitializedDylib.contains(&JD)) {
WrapperToCall = "__orc_rt_jit_dlupdate_wrapper";
dlupdate = true;
} else
InitializedDylib.insert(&JD);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deinitialize should take the JITDylib back out of the set, since the following sequence is valid:

  1. initialize.
  2. deinitialize.
  3. initialize.

Longer term we should probably rethink these operations on LLJIT, but for now this is a good compromise.

}

if (auto WrapperAddr = ES.lookup(
MainSearchOrder, J.mangleAndIntern("__orc_rt_jit_dlopen_wrapper"))) {
if (auto WrapperAddr =
ES.lookup(MainSearchOrder, J.mangleAndIntern(WrapperToCall))) {
if (dlupdate) {
int32_t result;
auto E = ES.callSPSWrapper<SPSDLUpdateSig>(WrapperAddr->getAddress(),
result, DSOHandles[&JD],
int32_t(ORC_RT_RTLD_LAZY));
if (E)
return E;
else if (result)
return make_error<StringError>("dlupdate failed",
inconvertibleErrorCode());
return Error::success();
}
return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(),
DSOHandles[&JD], JD.getName(),
int32_t(ORC_RT_RTLD_LAZY));
Expand All @@ -641,6 +663,7 @@ Error ORCPlatformSupport::deinitialize(orc::JITDylib &JD) {
return make_error<StringError>("dlclose failed",
inconvertibleErrorCode());
DSOHandles.erase(&JD);
InitializedDylib.erase(&JD);
} else
return WrapperAddr.takeError();
return Error::success();
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ MachOPlatform::standardRuntimeUtilityAliases() {
{"___orc_rt_run_program", "___orc_rt_macho_run_program"},
{"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
{"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
{"___orc_rt_jit_dlupdate", "___orc_rt_macho_jit_dlupdate"},
{"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
{"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
{"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
Expand Down
Loading