changeset 253:5cfe4322c500

- improved support for older OS versions for dynloads dlGetLibraryPath
author Tassilo Philipp
date Mon, 15 May 2017 02:50:03 +0200
parents 047d2829bdf6
children 9d70178c1ded
files configure dynload/dynload.3 dynload/dynload_unix.c
diffstat 3 files changed, 52 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/configure	Sun May 14 02:29:55 2017 +0200
+++ b/configure	Mon May 15 02:50:03 2017 +0200
@@ -63,16 +63,24 @@
 done
 printf "PREFIX=${PREFIX:=/usr/local}\n" >>$C
 case ${TARGET:=`uname`} in
-  Linux)
+  Linux|GNU/kFreeBSD)
     if [ -z "${CFLAGS}" ]; then
       printf "CFLAGS=-fPIC\n" >>$C
     fi
     printf "LDLIBS=-lm -ldl\n" >>$C
     ;;
   OpenBSD)
+    if [ -z "${CFLAGS}" ]; then
+      # dl_iterate_phdr() got introduced in 3.7, so for older versions force DL_DLADDR_TO_LIBPATH
+      if (uname -r | grep '^\([0-2]\.\|3\.[0-6]\)' > /dev/null); then
+        printf "CFLAGS=-fPIC -DDL_DLADDR_TO_LIBPATH\n" >>$C
+      else
+        printf "CFLAGS=-fPIC\n" >>$C
+      fi
+    fi
     printf "LDLIBS=-lm\n" >>$C
     ;;
-  DragonFly|NetBSD)
+  NetBSD|DragonFly)
     if [ -z "${CFLAGS}" ]; then
       printf "CFLAGS=-fPIC\n" >>$C
     fi
@@ -85,12 +93,6 @@
     printf "LDLIBS=-lm\n" >>$C
     printf "RM=rm -f\n" >>$C
     ;;
-  GNU/kFreeBSD)
-    if [ -z "${CFLAGS}" ]; then
-      printf "CFLAGS=-fPIC\n" >>$C
-    fi
-    printf "LDLIBS=-lm -ldl\n" >>$C
-    ;;
   MacOSX|Darwin)
     # if Apple's libtool (not to be confused with GNU's) is available, which is according to libtool(1) "with -static [...] intended
     # to replace ar(5) and ranlib", use it - if it is shadowed by some install of GNU's libtool assume that a foreign environment is
@@ -168,7 +170,7 @@
     printf "CC=` (which cc gcc clang  ) | grep -v '^no ' | head -1`\n" >>$C
     printf "CXX=`(which CC g++ clang++) | grep -v '^no ' | head -1`\n" >>$C # C++ compiler traditionally named CC
     printf "CCC=\${CXX}\n" >>$C # Sun make's rules use CCC for c++ compiler
-    printf "LDLIBS=-lm\n" >>$C
+    printf "LDLIBS=-lm -ldl\n" >>$C
     ;;
   Minix)
     printf "CC=gcc\n" >>$C
--- a/dynload/dynload.3	Sun May 14 02:29:55 2017 +0200
+++ b/dynload/dynload.3	Mon May 15 02:50:03 2017 +0200
@@ -102,11 +102,11 @@
 .Fn dlSymsInit
 is not thread-safe on Darwin.
 .Fn dlGetLibraryPath
-will not work on Haiku when the library in question doesn't have the (default)
+will not work on the following platforms when the library in question doesn't have the (default)
 .Fn _init
 and
 .Fn _fini
-symbols exported (rare, but possible).
+symbols exported (rare, but possible): Haiku (all versions), OpenBSD < 3.7, NetBSD < 5.1, FreeBSD < 4.8
 .Sh CONFORMING TO
 The dynload library conforms to c99.
 .Ed
--- a/dynload/dynload_unix.c	Sun May 14 02:29:55 2017 +0200
+++ b/dynload/dynload_unix.c	Mon May 15 02:50:03 2017 +0200
@@ -68,7 +68,9 @@
 }
 
 
-/* prefer RTLD_NOLOAD for code below that merely checks lib names */
+
+/* for dlopen-based dlGetLibraryPath impls below, prefer RTLD_NOLOAD */
+/* that merely checks lib names */
 #if defined(RTLD_NOLOAD)
 #  define RTLD_LIGHTEST RTLD_NOLOAD
 #else
@@ -76,8 +78,29 @@
 #endif
 
 
-/* code for dlGetLibraryPath differs on Darwin */
-#if defined(OS_Darwin)
+/* code for dlGetLibraryPath is platform specific - if dlinfo() exists use */
+/* that (checked through existance of RTLD_DI_LINKMAP, usually a #define   */
+/* for dlinfo(), or by OS (always on Solaris where it's from, usually on   */
+/* Linux, where the flag might be an enum instead, ...) */
+#if defined(RTLD_DI_LINKMAP) || defined(OS_SunOS) || (defined(OS_Linux) && !defined(DL_DLADDR_TO_LIBPATH))
+
+#include <link.h>
+
+int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
+{
+  struct link_map* p;
+  int l = -1;
+  if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) {
+    l = strlen(p->l_name);
+    if(l < bufSize) /* l+'\0' <= bufSize */
+      strcpy(sOut, p->l_name);
+  }
+  return l+1; /* strlen + '\0' */
+}
+
+
+/* specific implementation needed on Darwin -----> */
+#elif defined(OS_Darwin)
 
 #include <stdint.h>
 #include <mach-o/dyld.h>
@@ -114,9 +137,10 @@
   return l+1; /* strlen + '\0' */
 }
 
-#elif defined(OS_OpenBSD) /* doesn't have dlinfo() but dl_iterate_phdr() --> */
 
-/* @@@ dl_iterate_phdr() only exists on OpenBSD >= 3.7 */
+/* OpenBSD >= 3.7 has dl_iterate_phdr(), use it if not explicitly requesting */
+/* to use dladdr()-based guessing (set by configure) -----> */
+#elif defined(OS_OpenBSD) && !defined(DL_DLADDR_TO_LIBPATH)
 
 #include <sys/types.h>
 #include <link.h>
@@ -152,55 +176,21 @@
   return dl_iterate_phdr(iter_phdr_cb, &d);
 }
 
-#elif defined(OS_BeOS) /* neither dlinfo(), nor dl_iterate_phdr(), but ltdl stuff*/
 
-#if 0
-#include <ltdl.h>
-
-typedef struct { // @@@share
-  DLLib* pLib;
-  char*  sOut;
-  int    bufSize;
-} iter_phdr_data;
+/* fallback to dladdr() hack */
+#else
 
-static int handle_map_cb(lt_dlhandle h, void* data)
-{
-  int l = -1;
-  iter_phdr_data* d = (iter_phdr_data*)data;
-  /* same idea as with dl_iterate_phdr, see above */
-  const lt_dlinfo* dli = lt_dlgetinfo(h);
-  if(dli) {
-    void* lib = dlopen(dli->filename, RTLD_LIGHTEST);
-    if(lib) {
-      dlclose(lib);
-      if(lib == (void*)d->pLib) {
-        l = strlen(dli->filename);
-        if(l < d->bufSize) /* l+'\0' <= bufSize */
-          strcpy(d->sOut, dli->filename);
-      }
-    }
-  }
-  return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */
-}
+/* if nothing else is available, fall back to guessing using dladdr() - this */
+/* might not always work, as it's trying to getit via the _fini() symbol,    */
+/* which is usually defined in ELF files, but not guaranteed                 */
+
+/* @@@Note: On some platforms this might be improved, e.g. on BeOS we have */
+/* lt_dlgetinfo, which requires iterating over ltdl stuff, but was unable  */
+/* to get that to work (would also introduce a link dependency on libltdl) */
 
 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
 {
-  iter_phdr_data d = { pLib, sOut, bufSize };
-  lt_dlinterface_id ii = lt_dlinterface_register("not_sure_here...", NULL);
-  int l = lt_dlhandle_map(ii, handle_map_cb, &d);
-  lt_dlinterface_free(ii);
-  return l;
-}
-#endif
-
-/* we have lt_dlgetinfo on BeOS, which requires iterating over ltdl stuff, */
-/* but was unable to get that to work (would also have introduced a link   */
-/* dependency on libltdl); so do a hacky dladdr() based attempt, instead,  */
-/* which might not always work, but probably is ok for nearly all libs     */
-
-int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
-{
-  /* BeOS uses ELF, cross fingers that .so is standard and look for _fini */
+  /* cross fingers that shared object is standard ELF and look for _fini */
   int l = -1;
   void* s = dlsym((void*)pLib, "_fini");
   if(s) {
@@ -214,21 +204,5 @@
   return l+1; /* strlen + '\0' */
 }
 
-#else /* use dlinfo() --> */
-
-#include <link.h>
-
-int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
-{
-  struct link_map* p;
-  int l = -1;
-  if(dlinfo(pLib, RTLD_DI_LINKMAP, &p) == 0) {
-    l = strlen(p->l_name);
-    if(l < bufSize) /* l+'\0' <= bufSize */
-      strcpy(sOut, p->l_name);
-  }
-  return l+1; /* strlen + '\0' */
-}
-
 #endif