Fix libdl library internal implementation 72/202372/3 tizen_5.5_tv accepted/tizen/5.5/unified/20191031.014931 accepted/tizen/5.5/unified/mobile/hotfix/20201027.075120 accepted/tizen/5.5/unified/wearable/hotfix/20201027.112317 accepted/tizen/unified/20190328.234720 submit/tizen/20190328.143837 submit/tizen_5.5/20191031.000005 submit/tizen_5.5_mobile_hotfix/20201026.185105 submit/tizen_5.5_wearable_hotfix/20201026.184304 tizen_5.5.m2_release
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Wed, 27 Mar 2019 13:00:43 +0000 (16:00 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Thu, 28 Mar 2019 13:05:03 +0000 (16:05 +0300)
 Internal calls to __libc_dl* of libc library do not match
the API of the libdl library so we use the libdl library to
implement the internal::dl* API.

Change-Id: I2954df0bdae2132408a78c337f38ffbbf778ac18
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
src/core/internal_libdl.cpp

index 74e9d9d..e4b1865 100644 (file)
@@ -1,4 +1,7 @@
 #include "internal_libdl.h"
+#include "compiler.h"
+#include "common.h"
+#include "log.h"
 
 // private libc interface
 #define __RTLD_DLOPEN   0x80000000
@@ -9,19 +12,60 @@ extern "C" int __libc_dlclose(void *handle);
 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