I attach an updated patch. On further investigation, I see that dladdr *is* in libc for glibc >= 2.34 (according to your note in libdl.m4) so I've adjusted the guards accordingly. Now, the /proc parser is used only on Linux, when either uClibc is in use, or glibc >= 2 (for getline(), existing constraint) and < 2.34 (2.34 was released in August 2021).
I have invented some local symbols in the header file to separate the rather involved logic of deciding which version of the code to use (now at the top) from the places where the different bits of code are actually guarded. My patch is incomplete: it unconditionally uses libdl.m4, meaning libdl will always be linked on systems that have it. I appreciate this is what we're trying to avoid! I'm unclear what the best way to fix this is. Should I move the test for which code to use (i.e. Windows, libdl or /proc) to configure.ac, and introduce an automake conditional to guard the addition of libdl to the LIBS variable? -- Web: rrt.sc3d.org
From 64eff4e1cdf66944d8140e88314d38213a689963 Mon Sep 17 00:00:00 2001 From: Reuben Thomas <[email protected]> Date: Sun, 30 Nov 2025 15:07:35 +0000 Subject: [PATCH] relocatable-lib{,-lgpl}: use dladdr to get path to shared library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is portable (in POSIX:2024 [1]), so use it on all systems where we don’t already have special-case code (that is, non-Windows non-Linux systems), and on Linux where dladdr is in libc or we can’t use the /proc-parsing code (that is, not uClibc or glibc >= 2 and < 2.34). [1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/dladdr.html --- lib/relocatable.c | 40 ++++++++++++++++++++++++------------ m4/libdl.m4 | 2 +- modules/relocatable-lib | 3 +++ modules/relocatable-lib-lgpl | 2 ++ 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/relocatable.c b/lib/relocatable.c index 15b3bc442d..ed3b1e0f3c 100644 --- a/lib/relocatable.c +++ b/lib/relocatable.c @@ -71,6 +71,21 @@ # define GetModuleFileName GetModuleFileNameA #endif +/* We have special code for two types of system: non-Cygwin Windows, and + Linux where dladdr is in a separate library (uClibc and glibc < 2.34). + Need glibc >= 2, for getline(). + + Otherwise, use dladdr. +*/ +#if defined __linux__ && (defined __UCLIBC__ || ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ < 34))) +#define _GL_USE_PROCFS 1 +#elif (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ +#define _GL_USE_WIN32 1 +#else +#define _GL_USE_DLADDR 1 +#include <dlfcn.h> +#endif + /* Faked cheap 'bool'. */ #undef bool #undef false @@ -318,10 +333,9 @@ static char *shared_library_fullname; #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows only. - On Cygwin, it is better to use the Cygwin provided /proc interface, than - to use native Windows API and cygwin_conv_to_posix_path, because it - supports longer file names - (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */ + On Cygwin, it is better to use dladdr, than to use native Windows + API and cygwin_conv_to_posix_path, because it supports longer file + names (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */ /* Determine the full pathname of the shared library when it is loaded. @@ -402,12 +416,8 @@ _DLL_InitTerm (unsigned long hModule, unsigned long ulFlag) static void find_shared_library_fullname () { -#if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__ - /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline() - function. - Cygwin >= 1.5 has /proc/self/maps and the getline() function too. - But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on - Cygwin 1.7. */ +#if _GL_USE_PROCFS + /* Linux has /proc/self/maps. But it is costly: ca. 0.3 ms. */ FILE *fp; /* Open the current process' maps file. It describes one VMA per line. */ @@ -449,18 +459,22 @@ find_shared_library_fullname () } fclose (fp); } +#elif _GL_USE_DLADDR + Dl_info info; + dladdr (find_shared_library_fullname, &info); + if (info.dli_fname != NULL) + shared_library_fullname = strdup (info.dli_fname); #endif } #endif /* Native Windows / EMX / Unix */ /* Return the full pathname of the current shared library. - Return NULL if unknown. - Guaranteed to work only on Linux, EMX, Cygwin, and native Windows. */ + Return NULL if unknown. */ static char * get_shared_library_fullname () { -#if !(defined _WIN32 && !defined __CYGWIN__) && !defined __EMX__ +#if !_GL_USE_WIN32 static bool tried_find_shared_library_fullname; if (!tried_find_shared_library_fullname) { diff --git a/m4/libdl.m4 b/m4/libdl.m4 index 4b4357b7f8..839b053af5 100644 --- a/m4/libdl.m4 +++ b/m4/libdl.m4 @@ -15,7 +15,7 @@ AC_DEFUN([gl_LIBDL], dnl dlopen, dlsym are dnl - in libc on glibc >= 2.34, musl libc, macOS, FreeBSD, NetBSD, OpenBSD, dnl AIX, Solaris, Cygwin, Haiku, - dnl - in a separate libdl on glibc < 2.34, Android. + dnl - in a separate libdl on glibc < 2.34, Android, uClibc. AC_CACHE_CHECK([for library needed for dlopen and dlsym], [gl_cv_lib_dl], [AC_LINK_IFELSE( diff --git a/modules/relocatable-lib b/modules/relocatable-lib index 0d59464fe6..9500fb0eba 100644 --- a/modules/relocatable-lib +++ b/modules/relocatable-lib @@ -7,6 +7,7 @@ doc/relocatable.texi lib/relocatable.h lib/relocatable.c lib/relocatable.valgrind +m4/libdl.m4 m4/relocatable-lib.m4 m4/build-to-host.m4 @@ -19,8 +20,10 @@ gl_RELOCATABLE_LIBRARY if test $RELOCATABLE = yes; then AC_LIBOBJ([relocatable]) fi +gl_LIBDL Makefile.am: +lib_LDFLAGS += $(LIBDL) Include: "relocatable.h" diff --git a/modules/relocatable-lib-lgpl b/modules/relocatable-lib-lgpl index b8ecb51ef8..340879b033 100644 --- a/modules/relocatable-lib-lgpl +++ b/modules/relocatable-lib-lgpl @@ -18,9 +18,11 @@ gl_RELOCATABLE_LIBRARY if test $RELOCATABLE = yes; then AC_LIBOBJ([relocatable]) fi +gl_LIBDL Makefile.am: DEFS += -DNO_XMALLOC +lib_LDFLAGS += $(LIBDL) Include: "relocatable.h" -- 2.43.0
