mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] [RFC] Implement the _dl_find_object interface
@ 2026-02-04 23:23 Luciano Lo Giudice
  2026-02-05 20:19 ` Szabolcs Nagy
  0 siblings, 1 reply; 8+ messages in thread
From: Luciano Lo Giudice @ 2026-02-04 23:23 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 4347 bytes --]

If we look at  the unwinder logic in libgcc, we will notice that outside of
glibc, it uses `dl_iterate_phdr` to locate the .eh_frame section for a
specific program counter value [1].

The issue with their approach is that they use a global cache [2], which is
not protected by any locks. This is presumably because they assume that
`dl_iterate_phdr` provides mutual exclusion by itself. In musl, however,
the dynamic linker doesn't exactly do that, and as such, it appears that
C++ exceptions (and anything that uses the `_Unwind_Find_FDE` interface)
are unsafe in a multi-threaded scenario.

The obvious fix to this would be to file a bug for libgcc and get it fixed
there, but there's another option that also doesn't involve changing the
locking protocol in the dynamic linker: Some time ago, glibc implemented a
new interface called `_dl_find_object` [3], whose main purpose was to
improve the performance of the unwinder used in C++ programs. As such, musl
itself can do the same thing and in addition to fixing this bug, also
obtain a slight performance boost for the described scenario, since this
new interface would only acquire the dynamic linker's read lock once
instead of multiple times.

I'm attaching the patch inline in this message as it's a short one. Any
questions, comments or critiques are welcome.

[1]:
https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2-fde-dip.c#L569
[2]:
https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2-fde-dip.c#L156
[3]:
https://git.zx2c4.com/glibc/commit/elf?id=5d28a8962dcb6ec056b81d730e3c6fb57185a210

--------------------------------------
diff --git a/include/dlfcn.h b/include/dlfcn.h
index 13ab71dd..4d794cbd 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -31,8 +31,35 @@ typedef struct {
  const char *dli_sname;
  void *dli_saddr;
 } Dl_info;
+
+#ifdef __x86_64__
+# define DLFO_STRUCT_HAS_EH_DBASE 0
+#else
+# define DLFO_STRUCT_HAS_EH_DBASE 1
+#endif
+
+#include <bits/alltypes.h>
+
+#define DLFO_FLAG_SFRAME   1
+
+struct dl_find_object {
+    unsigned long long dlfo_flags;
+    void *dlfo_map_start;
+    void *dlfo_map_end;
+    struct link_map *dlfo_link_map;
+    void *dlfo_eh_frame;
+#if DLFO_STRUCT_HAS_EH_DBASE
+    void *dlfo_eh_dbase;
+#  if __LONG_MAX == 0x7fffffffL
+    unsigned int __pad1;
+#  endif
+#endif
+    unsigned long long __extra[7];
+};
+
 int dladdr(const void *, Dl_info *);
 int dlinfo(void *, int, void *);
+int _dl_find_object(void *, struct dl_find_object *);
 #endif

 #if _REDIR_TIME64
diff --git a/include/elf.h b/include/elf.h
index d6ae539a..ff196ffa 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -612,6 +612,7 @@ typedef struct {
 #define PT_GNU_STACK 0x6474e551
 #define PT_GNU_RELRO 0x6474e552
 #define PT_GNU_PROPERTY 0x6474e553
+#define PT_GNU_SFRAME 0x6474e554
 #define PT_LOSUNW 0x6ffffffa
 #define PT_SUNWBSS 0x6ffffffa
 #define PT_SUNWSTACK 0x6ffffffb
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 715948f4..2195017c 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -2437,3 +2437,44 @@ static void error_impl(const char *fmt, ...)
 static void error_noop(const char *fmt, ...)
 {
 }
+
+int _dl_find_object(void *addr, struct dl_find_object *obj)
+{
+ struct dso *p;
+ Phdr *phdr;
+ size_t cnt, esize;
+ unsigned int read;
+
+ pthread_rwlock_rdlock(&lock);
+ p = addr2dso((size_t)addr);
+ pthread_rwlock_unlock(&lock);
+
+ if (!p) return -1;
+
+ memset(obj, 0, sizeof(*obj));
+ obj->dlfo_map_start = p->map;
+ obj->dlfo_map_end = p->map + p->map_len;
+ obj->dlfo_link_map = (struct link_map *)p;
+#if DLFO_STRUCT_HAS_EH_DBASE
+ obj->dlfo_eh_dbase = p->got;
+#endif
+
+ phdr = p->phdr;
+ cnt = p->phnum;
+ esize = p->phentsize;
+ read = 0;
+
+ for (; cnt--; phdr = (void *)((char *)phdr + esize)) {
+ if (phdr->p_type == PT_GNU_EH_FRAME) {
+ obj->dlfo_eh_frame = laddr(p, phdr->p_vaddr);
+ read |= 1;
+ } else if (phdr->p_type == PT_GNU_SFRAME) {
+ obj->dlfo_flags |= DLFO_FLAG_SFRAME;
+ read |= 2;
+ }
+
+ if (read == 3) break;
+ }
+
+ return 0;
+}
diff --git a/src/dl_find_object.c b/src/dl_find_object.c
new file mode 100644
index 00000000..918d76a7
--- /dev/null
+++ b/src/dl_find_object.c
@@ -0,0 +1,10 @@
+#define _GNU_SOURCE
+#include <dlfcn.h>
+
+static int
+stub_dl_find_object (void *a, struct dl_find_object *o)
+{
+  return (-1);
+}
+
+weak_alias (stub_dl_find_object, _dl_find_object);

[-- Attachment #2: Type: text/html, Size: 5312 bytes --]

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [musl] [RFC] Implement the _dl_find_object interface
  2026-02-04 23:23 [musl] [RFC] Implement the _dl_find_object interface Luciano Lo Giudice
@ 2026-02-05 20:19 ` Szabolcs Nagy
  2026-02-06 20:11   ` Luciano Lo Giudice
  2026-02-07  0:51   ` Rich Felker
  0 siblings, 2 replies; 8+ messages in thread
From: Szabolcs Nagy @ 2026-02-05 20:19 UTC (permalink / raw)
  To: Luciano Lo Giudice; +Cc: musl

* Luciano Lo Giudice <lmlogiudice@gmail.com> [2026-02-04 20:23:04 -0300]:
> If we look at  the unwinder logic in libgcc, we will notice that outside of
> glibc, it uses `dl_iterate_phdr` to locate the .eh_frame section for a
> specific program counter value [1].
> 
> The issue with their approach is that they use a global cache [2], which is
> not protected by any locks. This is presumably because they assume that
> `dl_iterate_phdr` provides mutual exclusion by itself. In musl, however,
> the dynamic linker doesn't exactly do that, and as such, it appears that
> C++ exceptions (and anything that uses the `_Unwind_Find_FDE` interface)
> are unsafe in a multi-threaded scenario.

glibc has a (recursive) lock around the loop in dl_iterate_phdr,
this is a bug as it exposes internal lock to the user callback
(may cause deadlock) and since the loop can run for a long time
it can be a scalability issue for multithread code doing unwinds
concurrently. however libgcc relies on the lock so not fixed.
cant find bugzilla entry only
https://sourceware.org/pipermail/libc-help/2020-May/005276.html

> 
> The obvious fix to this would be to file a bug for libgcc and get it fixed
> there, but there's another option that also doesn't involve changing the
> locking protocol in the dynamic linker: Some time ago, glibc implemented a
> new interface called `_dl_find_object` [3], whose main purpose was to
> improve the performance of the unwinder used in C++ programs. As such, musl
> itself can do the same thing and in addition to fixing this bug, also
> obtain a slight performance boost for the described scenario, since this
> new interface would only acquire the dynamic linker's read lock once
> instead of multiple times.

i think it makes sense to report the libgcc bug.
(i'd expect the libgcc maintainers to require the defacto lock
in libc, however this is not documented currently)

note that glibc uses a version check + retry lock-free algorithm
in _dl_find_object for performane, musl could do this simpler
as it does not have to deal with dlclose. (e.g. dladdr could be
lock-free)

one issue with the _dl_find_object solution is deployment:
it will take time to enable its use in libgcc_s by default
since we want to allow users to build old musl code with a
new compiler so a new symbol in libgcc is problematic.

> 
> I'm attaching the patch inline in this message as it's a short one. Any
> questions, comments or critiques are welcome.
> 
> [1]:
> https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2-fde-dip.c#L569
> [2]:
> https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2-fde-dip.c#L156
> [3]:
> https://git.zx2c4.com/glibc/commit/elf?id=5d28a8962dcb6ec056b81d730e3c6fb57185a210
> 
> --------------------------------------
> diff --git a/include/dlfcn.h b/include/dlfcn.h
> index 13ab71dd..4d794cbd 100644
> --- a/include/dlfcn.h
> +++ b/include/dlfcn.h
> @@ -31,8 +31,35 @@ typedef struct {
>   const char *dli_sname;
>   void *dli_saddr;
>  } Dl_info;
> +
> +#ifdef __x86_64__
> +# define DLFO_STRUCT_HAS_EH_DBASE 0
> +#else
> +# define DLFO_STRUCT_HAS_EH_DBASE 1
> +#endif

this should be in a bits/ header, not generic

> +
> +#include <bits/alltypes.h>
> +
> +#define DLFO_FLAG_SFRAME   1
> +
> +struct dl_find_object {
> +    unsigned long long dlfo_flags;
> +    void *dlfo_map_start;
> +    void *dlfo_map_end;
> +    struct link_map *dlfo_link_map;
> +    void *dlfo_eh_frame;
> +#if DLFO_STRUCT_HAS_EH_DBASE
> +    void *dlfo_eh_dbase;
> +#  if __LONG_MAX == 0x7fffffffL
> +    unsigned int __pad1;
> +#  endif
> +#endif
> +    unsigned long long __extra[7];

this does not match the glibc abi/api on arm.

needs DLFO_STRUCT_HAS_EH_COUNT

> +};
> +
>  int dladdr(const void *, Dl_info *);
>  int dlinfo(void *, int, void *);
> +int _dl_find_object(void *, struct dl_find_object *);
>  #endif
> 
>  #if _REDIR_TIME64
> diff --git a/include/elf.h b/include/elf.h
> index d6ae539a..ff196ffa 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -612,6 +612,7 @@ typedef struct {
>  #define PT_GNU_STACK 0x6474e551
>  #define PT_GNU_RELRO 0x6474e552
>  #define PT_GNU_PROPERTY 0x6474e553
> +#define PT_GNU_SFRAME 0x6474e554
>  #define PT_LOSUNW 0x6ffffffa
>  #define PT_SUNWBSS 0x6ffffffa
>  #define PT_SUNWSTACK 0x6ffffffb
> diff --git a/ldso/dynlink.c b/ldso/dynlink.c
> index 715948f4..2195017c 100644
> --- a/ldso/dynlink.c
> +++ b/ldso/dynlink.c
> @@ -2437,3 +2437,44 @@ static void error_impl(const char *fmt, ...)
>  static void error_noop(const char *fmt, ...)
>  {
>  }
> +
> +int _dl_find_object(void *addr, struct dl_find_object *obj)
> +{
> + struct dso *p;
> + Phdr *phdr;
> + size_t cnt, esize;
> + unsigned int read;
> +
> + pthread_rwlock_rdlock(&lock);
> + p = addr2dso((size_t)addr);
> + pthread_rwlock_unlock(&lock);
> +
> + if (!p) return -1;
> +
> + memset(obj, 0, sizeof(*obj));
> + obj->dlfo_map_start = p->map;
> + obj->dlfo_map_end = p->map + p->map_len;
> + obj->dlfo_link_map = (struct link_map *)p;
> +#if DLFO_STRUCT_HAS_EH_DBASE
> + obj->dlfo_eh_dbase = p->got;
> +#endif
> +
> + phdr = p->phdr;
> + cnt = p->phnum;
> + esize = p->phentsize;
> + read = 0;
> +
> + for (; cnt--; phdr = (void *)((char *)phdr + esize)) {
> + if (phdr->p_type == PT_GNU_EH_FRAME) {
> + obj->dlfo_eh_frame = laddr(p, phdr->p_vaddr);
> + read |= 1;
> + } else if (phdr->p_type == PT_GNU_SFRAME) {
> + obj->dlfo_flags |= DLFO_FLAG_SFRAME;
> + read |= 2;
> + }
> +
> + if (read == 3) break;
> + }
> +
> + return 0;
> +}
> diff --git a/src/dl_find_object.c b/src/dl_find_object.c
> new file mode 100644
> index 00000000..918d76a7
> --- /dev/null
> +++ b/src/dl_find_object.c
> @@ -0,0 +1,10 @@
> +#define _GNU_SOURCE
> +#include <dlfcn.h>
> +
> +static int
> +stub_dl_find_object (void *a, struct dl_find_object *o)
> +{
> +  return (-1);
> +}
> +
> +weak_alias (stub_dl_find_object, _dl_find_object);

this api must work with static linking

if the symbol is present it will be used instead
of dl_iterate_phdr

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [musl] [RFC] Implement the _dl_find_object interface
  2026-02-05 20:19 ` Szabolcs Nagy
@ 2026-02-06 20:11   ` Luciano Lo Giudice
  2026-02-06 21:20     ` Szabolcs Nagy
  2026-02-07  0:51   ` Rich Felker
  1 sibling, 1 reply; 8+ messages in thread
From: Luciano Lo Giudice @ 2026-02-06 20:11 UTC (permalink / raw)
  To: Luciano Lo Giudice, musl

[-- Attachment #1: Type: text/plain, Size: 1194 bytes --]

> i think it makes sense to report the libgcc bug.
> (i'd expect the libgcc maintainers to require the defacto lock
> in libc, however this is not documented currently)

Agreed. The reason I suggested this new interface is that I've seen that in
the past some projects haven't been
receptive to the idea of musl-specific workarounds since detecting this
libc is not as straightforward as they'd like.
Still, I agree it merits reporting this issue.

> note that glibc uses a version check + retry lock-free algorithm
> in _dl_find_object for performane, musl could do this simpler
> as it does not have to deal with dlclose. (e.g. dladdr could be
> lock-free)

Indeed. I personally think musl could use a lightweight RCU scheme for the
dynamic linker, but that's a
discussion for another day.

> this should be in a bits/ header, not generic

I'm OK with this, but there's no bits/header where this would fit nicely.
There's alltypes.h, but putting this
definition there doesn't look good to me. Should I create a new header for
this?

> this does not match the glibc abi/api on arm.
> needs DLFO_STRUCT_HAS_EH_COUNT
> this api must work with static linking

Ack.

(Thanks for the review, btw).

[-- Attachment #2: Type: text/html, Size: 1684 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [musl] [RFC] Implement the _dl_find_object interface
  2026-02-06 20:11   ` Luciano Lo Giudice
@ 2026-02-06 21:20     ` Szabolcs Nagy
  2026-02-06 23:28       ` Luciano Lo Giudice
  0 siblings, 1 reply; 8+ messages in thread
From: Szabolcs Nagy @ 2026-02-06 21:20 UTC (permalink / raw)
  To: Luciano Lo Giudice; +Cc: musl

* Luciano Lo Giudice <lmlogiudice@gmail.com> [2026-02-06 17:11:03 -0300]:
> > this should be in a bits/ header, not generic
> 
> I'm OK with this, but there's no bits/header where this would fit nicely.
> There's alltypes.h, but putting this
> definition there doesn't look good to me. Should I create a new header for
> this?

new header in arch/generic/bits and arch/x86_64/bits

then instead of ifdef __x86_64__ just include bits/dlfcn.h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [musl] [RFC] Implement the _dl_find_object interface
  2026-02-06 21:20     ` Szabolcs Nagy
@ 2026-02-06 23:28       ` Luciano Lo Giudice
  2026-02-09 10:01         ` Florian Weimer
  0 siblings, 1 reply; 8+ messages in thread
From: Luciano Lo Giudice @ 2026-02-06 23:28 UTC (permalink / raw)
  To: Luciano Lo Giudice, musl

[-- Attachment #1: Type: text/plain, Size: 5853 bytes --]

Here's the newest patch, with the requested changes:

diff --git a/arch/arm/bits/dlfcn.h b/arch/arm/bits/dlfcn.h
new file mode 100644
index 00000000..c3c48482
--- /dev/null
+++ b/arch/arm/bits/dlfcn.h
@@ -0,0 +1,2 @@
+#define DLFO_STRUCT_HAS_EH_DBASE 1
+#define DLFO_STRUCT_HAS_EH_COUNT 1
diff --git a/arch/generic/bits/dlfcn.h b/arch/generic/bits/dlfcn.h
new file mode 100644
index 00000000..11d2dbec
--- /dev/null
+++ b/arch/generic/bits/dlfcn.h
@@ -0,0 +1,2 @@
+#define DLFO_STRUCT_HAS_EH_DBASE 1
+#define DLFO_STRUCT_HAS_EH_COUNT 0
diff --git a/arch/x86_64/bits/dlfcn.h b/arch/x86_64/bits/dlfcn.h
new file mode 100644
index 00000000..a000c9d7
--- /dev/null
+++ b/arch/x86_64/bits/dlfcn.h
@@ -0,0 +1,2 @@
+#define DLFO_STRUCT_HAS_EH_DBASE 0
+#define DLFO_STRUCT_HAS_EH_COUNT 0
diff --git a/include/dlfcn.h b/include/dlfcn.h
index 13ab71dd..b735e90e 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -25,14 +25,46 @@ void  *dlopen(const char *, int);
 void  *dlsym(void *__restrict, const char *__restrict);

 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+
+#include <bits/dlfcn.h>
+#include <bits/alltypes.h>
+
 typedef struct {
     const char *dli_fname;
     void *dli_fbase;
     const char *dli_sname;
     void *dli_saddr;
 } Dl_info;
+
+
+#define DLFO_FLAG_SFRAME   1
+
+struct dl_find_object {
+    unsigned long long dlfo_flags;
+    void *dlfo_map_start;
+    void *dlfo_map_end;
+    struct link_map *dlfo_link_map;
+    void *dlfo_eh_frame;
+#if DLFO_STRUCT_HAS_EH_DBASE
+    void *dlfo_eh_dbase;
+#  if __LONG_MAX == 0x7fffffffL
+    unsigned int __pad1;
+#  endif
+#endif
+#if DLFO_STRUCT_HAS_EH_COUNT
+    int dlfo_eh_count;
+    unsigned int __pad2;
+#endif
+    void *dlfo_sframe;
+#  if __LONG_MAX == 0x7fffffffL
+    unsigned int __pad3;
+#  endif
+    unsigned long long __extra[7];
+};
+
 int dladdr(const void *, Dl_info *);
 int dlinfo(void *, int, void *);
+int _dl_find_object(void *, struct dl_find_object *);
 #endif

 #if _REDIR_TIME64
diff --git a/include/elf.h b/include/elf.h
index d6ae539a..ff196ffa 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -612,6 +612,7 @@ typedef struct {
 #define PT_GNU_STACK    0x6474e551
 #define PT_GNU_RELRO    0x6474e552
 #define PT_GNU_PROPERTY    0x6474e553
+#define PT_GNU_SFRAME    0x6474e554
 #define PT_LOSUNW    0x6ffffffa
 #define PT_SUNWBSS    0x6ffffffa
 #define PT_SUNWSTACK    0x6ffffffb
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 715948f4..74326ac3 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -2437,3 +2437,48 @@ static void error_impl(const char *fmt, ...)
 static void error_noop(const char *fmt, ...)
 {
 }
+
+int _dl_find_object(void *addr, struct dl_find_object *obj)
+{
+    struct dso *p;
+    Phdr *phdr;
+    size_t cnt, esize;
+    unsigned int read;
+
+    pthread_rwlock_rdlock(&lock);
+    p = addr2dso((size_t)addr);
+    pthread_rwlock_unlock(&lock);
+
+    if (!p) return -1;
+
+    memset(obj, 0, sizeof(*obj));
+    obj->dlfo_map_start = p->map;
+    obj->dlfo_map_end = p->map + p->map_len;
+    obj->dlfo_link_map = (void *)p;
+#if DLFO_STRUCT_HAS_EH_DBASE
+    obj->dlfo_eh_dbase = p->got;
+#endif
+
+    phdr = p->phdr;
+    cnt = p->phnum;
+    esize = p->phentsize;
+    read = 0;
+
+    for (; cnt--; phdr = (void *)((char *)phdr + esize)) {
+        if (phdr->p_type == PT_GNU_EH_FRAME) {
+            obj->dlfo_eh_frame = laddr(p, phdr->p_vaddr);
+#if DLFO_STRUCT_HAS_EH_COUNT
+            obj->dlfo_eh_count = (int)(phdr->p_memsz / 8);
+#endif
+            read |= 1;
+        } else if (phdr->p_type == PT_GNU_SFRAME) {
+            obj->dlfo_flags |= DLFO_FLAG_SFRAME;
+            obj->dlfo_sframe = laddr(p, phdr->p_vaddr);
+            read |= 2;
+        }
+
+        if (read == 3) break;
+    }
+
+    return 0;
+}
diff --git a/src/ldso/dl_find_object.c b/src/ldso/dl_find_object.c
new file mode 100644
index 00000000..47c23f59
--- /dev/null
+++ b/src/ldso/dl_find_object.c
@@ -0,0 +1,76 @@
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <elf.h>
+#include <link.h>
+#include <string.h>
+#include "libc.h"
+
+#define AUX_CNT   38
+
+extern weak hidden const size_t _DYNAMIC[];
+
+static int
+dl_find_object_impl (void *addr, struct dl_find_object *obj)
+{
+  unsigned char *p;
+  ElfW(Phdr) *phdr, *eh_frame = 0, *sframe = 0;
+  size_t i, aux[AUX_CNT] = { 0 };
+  size_t base = 0, end = ~(size_t)0, cnt;
+  int found = 0;
+
+  for (i = 0; libc.auxv[i]; i += 2)
+    if (libc.auxv[i] < AUX_CNT)
+      aux[libc.auxv[i]] = libc.auxv[i + 1];
+
+  for (p = (void *)aux[AT_PHDR], cnt = aux[AT_PHNUM];
+      cnt; --cnt, p += aux[AT_PHENT]) {
+
+    phdr = (void *)p;
+    if (phdr->p_type == PT_PHDR) {
+      base = aux[AT_PHDR] - phdr->p_vaddr;
+      end = base + phdr->p_memsz;
+    }
+
+    if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
+      base = (size_t)_DYNAMIC - phdr->p_vaddr;
+    else if (phdr->p_type == PT_GNU_EH_FRAME)
+      eh_frame = phdr;
+    else if (phdr->p_type == PT_GNU_SFRAME)
+      sframe = phdr;
+  }
+
+  /* Test if the requested address is valid. */
+  for (p = (void *)aux[AT_PHDR], cnt = aux[AT_PHNUM];
+      cnt; --cnt, p += aux[AT_PHENT]) {
+
+    phdr = (void *)p;
+    if (phdr->p_type == PT_LOAD &&
+        (size_t)addr >= base + phdr->p_vaddr &&
+        (size_t)addr < base + phdr->p_vaddr + phdr->p_memsz) {
+      found = 1;
+      break;
+    }
+  }
+
+  if (!found) return -1;
+
+  memset(obj, 0, sizeof(*obj));
+  obj->dlfo_map_start = (void *)base;
+  obj->dlfo_map_end = (void *)end;
+
+  if (eh_frame) {
+    obj->dlfo_eh_frame = (void *)(base + eh_frame->p_vaddr);
+#if DLFO_STRUCT_HAS_EH_COUNT
+    obj->dlfo_eh_count = (int)(eh_frame->p_memsz / 8);
+#endif
+  }
+
+  if (sframe) {
+    obj->dlfo_sframe = (void *)(base + sframe->p_vaddr);
+    obj->dlfo_flags |= DLFO_FLAG_SFRAME;
+  }
+
+  return 0;
+}
+
+weak_alias (dl_find_object_impl, _dl_find_object);

[-- Attachment #2: Type: text/html, Size: 7042 bytes --]

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [musl] [RFC] Implement the _dl_find_object interface
  2026-02-05 20:19 ` Szabolcs Nagy
  2026-02-06 20:11   ` Luciano Lo Giudice
@ 2026-02-07  0:51   ` Rich Felker
  1 sibling, 0 replies; 8+ messages in thread
From: Rich Felker @ 2026-02-07  0:51 UTC (permalink / raw)
  To: Luciano Lo Giudice, musl

On Thu, Feb 05, 2026 at 09:19:06PM +0100, Szabolcs Nagy wrote:
> > --------------------------------------
> > diff --git a/include/dlfcn.h b/include/dlfcn.h
> > index 13ab71dd..4d794cbd 100644
> > --- a/include/dlfcn.h
> > +++ b/include/dlfcn.h
> > @@ -31,8 +31,35 @@ typedef struct {
> >   const char *dli_sname;
> >   void *dli_saddr;
> >  } Dl_info;
> > +
> > +#ifdef __x86_64__
> > +# define DLFO_STRUCT_HAS_EH_DBASE 0
> > +#else
> > +# define DLFO_STRUCT_HAS_EH_DBASE 1
> > +#endif
> 
> this should be in a bits/ header, not generic

Is there a legitimate reason the fields differ by arch? That's rather
an antipattern for adding new interfaces like this..

Rich

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [musl] [RFC] Implement the _dl_find_object interface
  2026-02-06 23:28       ` Luciano Lo Giudice
@ 2026-02-09 10:01         ` Florian Weimer
  2026-02-10 19:18           ` Luciano Lo Giudice
  0 siblings, 1 reply; 8+ messages in thread
From: Florian Weimer @ 2026-02-09 10:01 UTC (permalink / raw)
  To: Luciano Lo Giudice; +Cc: musl

* Luciano Lo Giudice:

> +    for (; cnt--; phdr = (void *)((char *)phdr + esize)) {
> +        if (phdr->p_type == PT_GNU_EH_FRAME) {
> +            obj->dlfo_eh_frame = laddr(p, phdr->p_vaddr);
> +#if DLFO_STRUCT_HAS_EH_COUNT
> +            obj->dlfo_eh_count = (int)(phdr->p_memsz / 8);
> +#endif

The dlfo_eh_count field is never used with PT_GNU_EH_FRAME, only with
PT_ARM_EXIDX.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [musl] [RFC] Implement the _dl_find_object interface
  2026-02-09 10:01         ` Florian Weimer
@ 2026-02-10 19:18           ` Luciano Lo Giudice
  0 siblings, 0 replies; 8+ messages in thread
From: Luciano Lo Giudice @ 2026-02-10 19:18 UTC (permalink / raw)
  To: Florian Weimer; +Cc: musl

[-- Attachment #1: Type: text/plain, Size: 6301 bytes --]

Hello Florian,

> The dlfo_eh_count field is never used with PT_GNU_EH_FRAME, only with
> PT_ARM_EXIDX.

Thanks, fixed.

Hello Rich,
> Is there a legitimate reason the fields differ by arch? That's rather
> an antipattern for adding new interfaces like this..

I don't know what glib's reasoning is, to be honest. I did it this way for
compatibility, but I guess
every field could be added regardless, with no consequences.

Here's the updated patch:

diff --git a/arch/arm/bits/dlfcn.h b/arch/arm/bits/dlfcn.h
new file mode 100644
index 00000000..d9a13e2c
--- /dev/null
+++ b/arch/arm/bits/dlfcn.h
@@ -0,0 +1,3 @@
+#define DLFO_STRUCT_HAS_EH_DBASE 1
+#define DLFO_STRUCT_HAS_EH_COUNT 1
+#define DLFO_EH_SEGMENT_TYPE PT_ARM_EXIDX
diff --git a/arch/generic/bits/dlfcn.h b/arch/generic/bits/dlfcn.h
new file mode 100644
index 00000000..ec70f4e6
--- /dev/null
+++ b/arch/generic/bits/dlfcn.h
@@ -0,0 +1,3 @@
+#define DLFO_STRUCT_HAS_EH_DBASE 1
+#define DLFO_STRUCT_HAS_EH_COUNT 0
+#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME
diff --git a/arch/x86_64/bits/dlfcn.h b/arch/x86_64/bits/dlfcn.h
new file mode 100644
index 00000000..e38879dd
--- /dev/null
+++ b/arch/x86_64/bits/dlfcn.h
@@ -0,0 +1,3 @@
+#define DLFO_STRUCT_HAS_EH_DBASE 0
+#define DLFO_STRUCT_HAS_EH_COUNT 0
+#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME
diff --git a/include/dlfcn.h b/include/dlfcn.h
index 13ab71dd..b735e90e 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -25,14 +25,46 @@ void  *dlopen(const char *, int);
 void  *dlsym(void *__restrict, const char *__restrict);

 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+
+#include <bits/dlfcn.h>
+#include <bits/alltypes.h>
+
 typedef struct {
  const char *dli_fname;
  void *dli_fbase;
  const char *dli_sname;
  void *dli_saddr;
 } Dl_info;
+
+
+#define DLFO_FLAG_SFRAME   1
+
+struct dl_find_object {
+    unsigned long long dlfo_flags;
+    void *dlfo_map_start;
+    void *dlfo_map_end;
+    struct link_map *dlfo_link_map;
+    void *dlfo_eh_frame;
+#if DLFO_STRUCT_HAS_EH_DBASE
+    void *dlfo_eh_dbase;
+#  if __LONG_MAX == 0x7fffffffL
+    unsigned int __pad1;
+#  endif
+#endif
+#if DLFO_STRUCT_HAS_EH_COUNT
+    int dlfo_eh_count;
+    unsigned int __pad2;
+#endif
+    void *dlfo_sframe;
+#  if __LONG_MAX == 0x7fffffffL
+    unsigned int __pad3;
+#  endif
+    unsigned long long __extra[7];
+};
+
 int dladdr(const void *, Dl_info *);
 int dlinfo(void *, int, void *);
+int _dl_find_object(void *, struct dl_find_object *);
 #endif

 #if _REDIR_TIME64
diff --git a/include/elf.h b/include/elf.h
index d6ae539a..ff196ffa 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -612,6 +612,7 @@ typedef struct {
 #define PT_GNU_STACK 0x6474e551
 #define PT_GNU_RELRO 0x6474e552
 #define PT_GNU_PROPERTY 0x6474e553
+#define PT_GNU_SFRAME 0x6474e554
 #define PT_LOSUNW 0x6ffffffa
 #define PT_SUNWBSS 0x6ffffffa
 #define PT_SUNWSTACK 0x6ffffffb
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 715948f4..31b2e247 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -2437,3 +2437,48 @@ static void error_impl(const char *fmt, ...)
 static void error_noop(const char *fmt, ...)
 {
 }
+
+int _dl_find_object(void *addr, struct dl_find_object *obj)
+{
+   struct dso *p;
+    Phdr *phdr;
+   size_t cnt, esize;
+   unsigned int read;
+
+   pthread_rwlock_rdlock(&lock);
+   p = addr2dso((size_t)addr);
+   pthread_rwlock_unlock(&lock);
+
+   if (!p) return -1;
+
+   memset(obj, 0, sizeof(*obj));
+   obj->dlfo_map_start = p->map;
+   obj->dlfo_map_end = p->map + p->map_len;
+   obj->dlfo_link_map = (void *)p;
+#if DLFO_STRUCT_HAS_EH_DBASE
+   obj->dlfo_eh_dbase = p->got;
+#endif
+
+   phdr = p->phdr;
+   cnt = p->phnum;
+   esize = p->phentsize;
+   read = 0;
+
+   for (; cnt--; phdr = (void *)((char *)phdr + esize)) {
+        if (phdr->p_type == DLFO_EH_SEGMENT_TYPE) {
+       obj->dlfo_eh_frame = laddr(p, phdr->p_vaddr);
+#if DLFO_STRUCT_HAS_EH_COUNT
+       obj->dlfo_eh_count = (int)(phdr->p_memsz / 8);
+#endif
+   read |= 1;
+    } else if (phdr->p_type == PT_GNU_SFRAME) {
+       obj->dlfo_flags |= DLFO_FLAG_SFRAME;
+       obj->dlfo_sframe = laddr(p, phdr->p_vaddr);
+       read |= 2;
+    }
+
+    if (read == 3) break;
+ }
+
+   return 0;
+}
diff --git a/src/ldso/dl_find_object.c b/src/ldso/dl_find_object.c
new file mode 100644
index 00000000..77a520a9
--- /dev/null
+++ b/src/ldso/dl_find_object.c
@@ -0,0 +1,76 @@
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <elf.h>
+#include <link.h>
+#include <string.h>
+#include "libc.h"
+
+#define AUX_CNT   38
+
+extern weak hidden const size_t _DYNAMIC[];
+
+static int
+dl_find_object_impl (void *addr, struct dl_find_object *obj)
+{
+  unsigned char *p;
+  ElfW(Phdr) *phdr, *eh_frame = 0, *sframe = 0;
+  size_t i, aux[AUX_CNT] = { 0 };
+  size_t base = 0, end = ~(size_t)0, cnt;
+  int found = 0;
+
+  for (i = 0; libc.auxv[i]; i += 2)
+    if (libc.auxv[i] < AUX_CNT)
+      aux[libc.auxv[i]] = libc.auxv[i + 1];
+
+  for (p = (void *)aux[AT_PHDR], cnt = aux[AT_PHNUM];
+      cnt; --cnt, p += aux[AT_PHENT]) {
+
+    phdr = (void *)p;
+    if (phdr->p_type == PT_PHDR) {
+      base = aux[AT_PHDR] - phdr->p_vaddr;
+      end = base + phdr->p_memsz;
+    }
+
+    if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
+      base = (size_t)_DYNAMIC - phdr->p_vaddr;
+    else if (phdr->p_type == DLFO_EH_SEGMENT_TYPE)
+      eh_frame = phdr;
+    else if (phdr->p_type == PT_GNU_SFRAME)
+      sframe = phdr;
+  }
+
+  /* Test if the requested address is valid. */
+  for (p = (void *)aux[AT_PHDR], cnt = aux[AT_PHNUM];
+      cnt; --cnt, p += aux[AT_PHENT]) {
+
+    phdr = (void *)p;
+    if (phdr->p_type == PT_LOAD &&
+        (size_t)addr >= base + phdr->p_vaddr &&
+        (size_t)addr < base + phdr->p_vaddr + phdr->p_memsz) {
+      found = 1;
+      break;
+    }
+  }
+
+  if (!found) return -1;
+
+  memset(obj, 0, sizeof(*obj));
+  obj->dlfo_map_start = (void *)base;
+  obj->dlfo_map_end = (void *)end;
+
+  if (eh_frame) {
+    obj->dlfo_eh_frame = (void *)(base + eh_frame->p_vaddr);
+#if DLFO_STRUCT_HAS_EH_COUNT
+    obj->dlfo_eh_count = (int)(eh_frame->p_memsz / 8);
+#endif
+  }
+
+  if (sframe) {
+    obj->dlfo_sframe = (void *)(base + sframe->p_vaddr);
+    obj->dlfo_flags |= DLFO_FLAG_SFRAME;
+  }
+
+  return 0;
+}
+
+weak_alias (dl_find_object_impl, _dl_find_object);

>
>

[-- Attachment #2: Type: text/html, Size: 7862 bytes --]

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-02-10 19:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-04 23:23 [musl] [RFC] Implement the _dl_find_object interface Luciano Lo Giudice
2026-02-05 20:19 ` Szabolcs Nagy
2026-02-06 20:11   ` Luciano Lo Giudice
2026-02-06 21:20     ` Szabolcs Nagy
2026-02-06 23:28       ` Luciano Lo Giudice
2026-02-09 10:01         ` Florian Weimer
2026-02-10 19:18           ` Luciano Lo Giudice
2026-02-07  0:51   ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).