#include "internal_libdl.h"
+#include "compiler.h"
+#include "common.h"
+#include "log.h"
// private libc interface
#define __RTLD_DLOPEN 0x80000000
namespace __swap {
namespace internal {
+static void *g_libdl_handle;
+
+static void *(*g_dlopen_ptr)(const char *filename, int flag);
+static void *(*g_dlsym_ptr)(void *handle, const char *symbol);
+static int (*g_dlclose_ptr)(void *handle);
+
+static bool dl_is_init()
+{
+ return g_dlopen_ptr && g_dlsym_ptr && g_dlclose_ptr;
+}
+
+static void dl_init()
+{
+ if (LIKELY(dl_is_init()))
+ return;
+
+ // The 'libdl' library can be loaded multiple times (in a multithreaded application)
+ // but that's fine because we're not going to unload it.
+ if (!g_libdl_handle) {
+ // FIXME: This path can be different on other platforms
+ g_libdl_handle = __libc_dlopen_mode("/lib/libdl.so.2", __RTLD_DLOPEN | RTLD_NOW);
+ if (!g_libdl_handle) {
+ LOGE("Not found libdl library");
+ die();
+ }
+ }
+
+ g_dlopen_ptr = (void *(*)(const char *, int))__libc_dlsym(g_libdl_handle, "dlopen");
+ g_dlsym_ptr = (void *(*)(void *, const char *))__libc_dlsym(g_libdl_handle, "dlsym");
+ g_dlclose_ptr = (int (*)(void *))__libc_dlsym(g_libdl_handle, "dlclose");
+
+ if (!dl_is_init()) {
+ LOGE("Cannot init libdl module: dlopen=%p dlsym=%p dlclose=%p",
+ g_dlopen_ptr, g_dlsym_ptr, g_dlclose_ptr);
+ die();
+ }
+}
+
void *dlopen(const char *filename, int flag) noexcept
{
- return __libc_dlopen_mode(filename, __RTLD_DLOPEN | flag);
+ dl_init();
+ return g_dlopen_ptr(filename, flag);
}
void *dlsym(void *handle, const char *symbol) noexcept
{
- return __libc_dlsym(handle, symbol);
+ dl_init();
+ return g_dlsym_ptr(handle, symbol);
}
int dlclose(void *handle) noexcept
{
- return __libc_dlclose(handle);
+ dl_init();
+ return g_dlclose_ptr(handle);
}
} // namespace internal