# HG changeset patch # User Tassilo Philipp # Date 1494809403 -7200 # Node ID 5cfe4322c500896717fbd14c47511309d4bff548 # Parent 047d2829bdf62faad24db212b29d16a78491f8a6 - improved support for older OS versions for dynloads dlGetLibraryPath diff -r 047d2829bdf6 -r 5cfe4322c500 configure --- 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 diff -r 047d2829bdf6 -r 5cfe4322c500 dynload/dynload.3 --- 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 diff -r 047d2829bdf6 -r 5cfe4322c500 dynload/dynload_unix.c --- 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 + +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 #include @@ -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 #include @@ -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 - -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 - -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