On Fri, 2 May 2025 at 02:30, Bruno Haible <br...@clisp.org> wrote: I don't think requiring -ldl is a "small" price to pay. It increases the > startup times of the programs linked to that library. Therefore how about > using dladdr only on those platforms where it is in libc? This would cover > all the platform that you mentioned, and on Cygwin it would be a speedup > (likely no system calls instead of reading from the /proc file system). >
I just re-read this, and realised that presumably this means that using dladdr would also be an improvement on Linux with glibc or uClibc, where currently we also read /proc? Which means that the /proc-reading code can be removed, as it is only used on the above-mentioned combinations plus Cygwin, which you already said would be faster with dladdr. I attach an updated patch. I have dealt with the shortcomings I previously identified: I check whether the path returned by dladdr is NULL before attempting to strdup it, and I add the same support to the relocatable-lib module. I have removed the previous Cygwin/Linux code in favour of this simpler, faster method. -- https://rrt.sc3d.org
From 68b2eb373be7a39f0ad6c025a988bfe5c9f6e96b Mon Sep 17 00:00:00 2001 From: Reuben Thomas <r...@sc3d.org> Date: Thu, 1 May 2025 20:45:19 +0100 Subject: [PATCH] relocatable-lib{,-lgpl}: use dladdr to get path to shared library This is simpler (and probably faster) than using /proc, and works on many more systems (dladdr is already implemented on most BSDs, for which previously we had no solution, and is even part of POSIX:2024[1]). [1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/dladdr.html --- lib/relocatable.c | 64 +++++++----------------------------- modules/relocatable-lib | 3 ++ modules/relocatable-lib-lgpl | 3 ++ 3 files changed, 18 insertions(+), 52 deletions(-) diff --git a/lib/relocatable.c b/lib/relocatable.c index 15b3bc442d..5a23a39100 100644 --- a/lib/relocatable.c +++ b/lib/relocatable.c @@ -71,6 +71,10 @@ # define GetModuleFileName GetModuleFileNameA #endif +#if !(defined _WIN32 && !defined __CYGWIN__) && !(defined __EMX__) +#include <dlfcn.h> +#endif + /* Faked cheap 'bool'. */ #undef bool #undef false @@ -318,10 +322,10 @@ 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,54 +406,10 @@ _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. */ - FILE *fp; - - /* Open the current process' maps file. It describes one VMA per line. */ - fp = fopen ("/proc/self/maps", "r"); - if (fp) - { - unsigned long address = (unsigned long) &find_shared_library_fullname; - for (;;) - { - unsigned long start, end; - int c; - - if (fscanf (fp, "%lx-%lx", &start, &end) != 2) - break; - if (address >= start && address <= end - 1) - { - /* Found it. Now see if this line contains a filename. */ - while (c = getc (fp), c != EOF && c != '\n' && c != '/') - continue; - if (c == '/') - { - size_t size; - int len; - - ungetc (c, fp); - shared_library_fullname = NULL; size = 0; - len = getline (&shared_library_fullname, &size, fp); - if (len >= 0) - { - /* Success: filled shared_library_fullname. */ - if (len > 0 && shared_library_fullname[len - 1] == '\n') - shared_library_fullname[len - 1] = '\0'; - } - } - break; - } - while (c = getc (fp), c != EOF && c != '\n') - continue; - } - fclose (fp); - } -#endif + Dl_info info; + dladdr (find_shared_library_fullname, &info); + if (info.dli_fname != NULL) + shared_library_fullname = strdup (info.dli_fname); } #endif /* Native Windows / EMX / Unix */ diff --git a/modules/relocatable-lib b/modules/relocatable-lib index 7cdca5ce0a..f3f8e15dff 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..da905347cd 100644 --- a/modules/relocatable-lib-lgpl +++ b/modules/relocatable-lib-lgpl @@ -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 @@ -18,9 +19,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