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

Reply via email to