|
|
Message-Id: <20251017-dlopen-use-rpath-of-caller-dso-v1-1-46c69eda1473@iscas.ac.cn>
Date: Fri, 17 Oct 2025 18:50:52 +0800
From: Vivian Wang <wangruikang@...as.ac.cn>
To: musl@...ts.openwall.com
Cc: matthewcroughan <matt@...ughan.sh>
Subject: [PATCH] ldso: Use rpath of dso of caller in dlopen
Grab the return address using an arch-specific wrapper dlopen calling a
generic __dlopen (analogous to dlsym and __dlsym), and use it to find
the dso to use as needed_by for load_library in __dlopen. This way, when
a dso calls dlopen, the library is searched from *this* dso's rpath.
This feature is used by shared libraries that dlopen on demand other
shared libraries found in nonstandard paths.
This makes the behavior of DT_RUNPATH match glibc better. Also, since we
already use this behavior with libraries loaded with DT_NEEDED, adding
support for dlopen makes it more consistent.
By coincidence, both __dlsym and __dlopen take three arguments, the last
of which is the return address. Therefore all of the arch-specific
src/ldso/*/dlopen.s is just the corresponding dlsym.s with "dlsym"
replaced by "dlopen".
---
I am not subscribed to the mailing list, so please cc on reply. Thanks.
I have primarily tested this on aarch64. I'm not sure whether this
approach makes sense. Please advise.
One observation is that musl falls back to using rpath entries from the
entire needed_by chain, so this change in behavior shouldn't break
existing working use cases.
---
ldso/dynlink.c | 75 ++++++++++++++++++++++---------------------
src/internal/dynlink.h | 1 +
src/ldso/__dlopen.c | 10 ++++++
src/ldso/aarch64/dlopen.s | 6 ++++
src/ldso/arm/dlopen.s | 8 +++++
src/ldso/dlopen.c | 8 ++---
src/ldso/i386/dlopen.s | 11 +++++++
src/ldso/loongarch64/dlopen.s | 7 ++++
src/ldso/m68k/dlopen.s | 12 +++++++
src/ldso/microblaze/dlopen.s | 6 ++++
src/ldso/mips/dlopen.s | 17 ++++++++++
src/ldso/mips64/dlopen.s | 17 ++++++++++
src/ldso/mipsn32/dlopen.s | 17 ++++++++++
src/ldso/or1k/dlopen.s | 6 ++++
src/ldso/powerpc/dlopen.s | 8 +++++
src/ldso/powerpc64/dlopen.s | 11 +++++++
src/ldso/riscv32/dlopen.s | 6 ++++
src/ldso/riscv64/dlopen.s | 6 ++++
src/ldso/s390x/dlopen.s | 6 ++++
src/ldso/sh/dlopen.s | 11 +++++++
src/ldso/x32/dlopen.s | 7 ++++
src/ldso/x86_64/dlopen.s | 7 ++++
22 files changed, 221 insertions(+), 42 deletions(-)
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 715948f4..996d505a 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -2096,9 +2096,42 @@ static void prepare_lazy(struct dso *p)
lazy_head = p;
}
-void *dlopen(const char *file, int mode)
+static void *addr2dso(size_t a)
+{
+ struct dso *p;
+ size_t i;
+ if (DL_FDPIC) for (p=head; p; p=p->next) {
+ i = count_syms(p);
+ if (a-(size_t)p->funcdescs < i*sizeof(*p->funcdescs))
+ return p;
+ }
+ for (p=head; p; p=p->next) {
+ if (DL_FDPIC && p->loadmap) {
+ for (i=0; i<p->loadmap->nsegs; i++) {
+ if (a-p->loadmap->segs[i].p_vaddr
+ < p->loadmap->segs[i].p_memsz)
+ return p;
+ }
+ } else {
+ Phdr *ph = p->phdr;
+ size_t phcnt = p->phnum;
+ size_t entsz = p->phentsize;
+ size_t base = (size_t)p->base;
+ for (; phcnt--; ph=(void *)((char *)ph+entsz)) {
+ if (ph->p_type != PT_LOAD) continue;
+ if (a-base-ph->p_vaddr < ph->p_memsz)
+ return p;
+ }
+ if (a-(size_t)p->map < p->map_len)
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void *__dlopen(const char *file, int mode, void *ra)
{
- struct dso *volatile p, *orig_tail, *orig_syms_tail, *orig_lazy_head, *next;
+ struct dso *volatile p, *needed_by, *orig_tail, *orig_syms_tail, *orig_lazy_head, *next;
struct tls_module *orig_tls_tail;
size_t orig_tls_cnt, orig_tls_offset, orig_tls_align;
size_t i;
@@ -2108,6 +2141,9 @@ void *dlopen(const char *file, int mode)
if (!file) return head;
+ needed_by = addr2dso((size_t)ra);
+ if (!needed_by) needed_by = head;
+
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
pthread_rwlock_wrlock(&lock);
__inhibit_ptc();
@@ -2160,7 +2196,7 @@ void *dlopen(const char *file, int mode)
tail->next = 0;
p = 0;
goto end;
- } else p = load_library(file, head);
+ } else p = load_library(file, needed_by);
if (!p) {
error(noload ?
@@ -2231,39 +2267,6 @@ hidden int __dl_invalid_handle(void *h)
return 1;
}
-static void *addr2dso(size_t a)
-{
- struct dso *p;
- size_t i;
- if (DL_FDPIC) for (p=head; p; p=p->next) {
- i = count_syms(p);
- if (a-(size_t)p->funcdescs < i*sizeof(*p->funcdescs))
- return p;
- }
- for (p=head; p; p=p->next) {
- if (DL_FDPIC && p->loadmap) {
- for (i=0; i<p->loadmap->nsegs; i++) {
- if (a-p->loadmap->segs[i].p_vaddr
- < p->loadmap->segs[i].p_memsz)
- return p;
- }
- } else {
- Phdr *ph = p->phdr;
- size_t phcnt = p->phnum;
- size_t entsz = p->phentsize;
- size_t base = (size_t)p->base;
- for (; phcnt--; ph=(void *)((char *)ph+entsz)) {
- if (ph->p_type != PT_LOAD) continue;
- if (a-base-ph->p_vaddr < ph->p_memsz)
- return p;
- }
- if (a-(size_t)p->map < p->map_len)
- return 0;
- }
- }
- return 0;
-}
-
static void *do_dlsym(struct dso *p, const char *s, void *ra)
{
int use_deps = 0;
diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h
index 40c743e2..ce718927 100644
--- a/src/internal/dynlink.h
+++ b/src/internal/dynlink.h
@@ -106,6 +106,7 @@ struct fdpic_dummy_loadmap {
typedef void (*stage2_func)(unsigned char *, size_t *);
hidden void *__dlsym(void *restrict, const char *restrict, void *restrict);
+hidden void *__dlopen(const char *, int, void *restrict);
hidden void __dl_seterr(const char *, ...);
hidden int __dl_invalid_handle(void *);
diff --git a/src/ldso/__dlopen.c b/src/ldso/__dlopen.c
new file mode 100644
index 00000000..e8e381f3
--- /dev/null
+++ b/src/ldso/__dlopen.c
@@ -0,0 +1,10 @@
+#include <dlfcn.h>
+#include "dynlink.h"
+
+static void *stub_dlopen(const char *file, int mode, void *restrict ra)
+{
+ __dl_seterr("Dynamic loading not supported");
+ return 0;
+}
+
+weak_alias(stub_dlopen, __dlopen);
diff --git a/src/ldso/aarch64/dlopen.s b/src/ldso/aarch64/dlopen.s
new file mode 100644
index 00000000..a925317c
--- /dev/null
+++ b/src/ldso/aarch64/dlopen.s
@@ -0,0 +1,6 @@
+.global dlopen
+.hidden __dlopen
+.type dlopen,%function
+dlopen:
+ mov x2,x30
+ b __dlopen
diff --git a/src/ldso/arm/dlopen.s b/src/ldso/arm/dlopen.s
new file mode 100644
index 00000000..d6754b17
--- /dev/null
+++ b/src/ldso/arm/dlopen.s
@@ -0,0 +1,8 @@
+.syntax unified
+.text
+.global dlopen
+.hidden __dlopen
+.type dlopen,%function
+dlopen:
+ mov r2,lr
+ b __dlopen
diff --git a/src/ldso/dlopen.c b/src/ldso/dlopen.c
index 69372a22..888d8bdd 100644
--- a/src/ldso/dlopen.c
+++ b/src/ldso/dlopen.c
@@ -1,10 +1,6 @@
-#include <dlfcn.h>
#include "dynlink.h"
-static void *stub_dlopen(const char *file, int mode)
+void *dlopen(const char *file, int mode)
{
- __dl_seterr("Dynamic loading not supported");
- return 0;
+ return __dlopen(file, mode, 0);
}
-
-weak_alias(stub_dlopen, dlopen);
diff --git a/src/ldso/i386/dlopen.s b/src/ldso/i386/dlopen.s
new file mode 100644
index 00000000..ec98a52c
--- /dev/null
+++ b/src/ldso/i386/dlopen.s
@@ -0,0 +1,11 @@
+.text
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ push (%esp)
+ push 12(%esp)
+ push 12(%esp)
+ call __dlopen
+ add $12,%esp
+ ret
diff --git a/src/ldso/loongarch64/dlopen.s b/src/ldso/loongarch64/dlopen.s
new file mode 100644
index 00000000..aa014d37
--- /dev/null
+++ b/src/ldso/loongarch64/dlopen.s
@@ -0,0 +1,7 @@
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ move $a2, $ra
+ la.global $t0, __dlopen
+ jr $t0
diff --git a/src/ldso/m68k/dlopen.s b/src/ldso/m68k/dlopen.s
new file mode 100644
index 00000000..5d839ca2
--- /dev/null
+++ b/src/ldso/m68k/dlopen.s
@@ -0,0 +1,12 @@
+.text
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ move.l (%sp),-(%sp)
+ move.l 12(%sp),-(%sp)
+ move.l 12(%sp),-(%sp)
+ lea __dlopen-.-8,%a1
+ jsr (%pc,%a1)
+ add.l #12,%sp
+ rts
diff --git a/src/ldso/microblaze/dlopen.s b/src/ldso/microblaze/dlopen.s
new file mode 100644
index 00000000..940b88c9
--- /dev/null
+++ b/src/ldso/microblaze/dlopen.s
@@ -0,0 +1,6 @@
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ brid __dlopen
+ add r7, r15, r0
diff --git a/src/ldso/mips/dlopen.s b/src/ldso/mips/dlopen.s
new file mode 100644
index 00000000..791ee8d8
--- /dev/null
+++ b/src/ldso/mips/dlopen.s
@@ -0,0 +1,17 @@
+.set noreorder
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ lui $gp, %hi(_gp_disp)
+ addiu $gp, %lo(_gp_disp)
+ addu $gp, $gp, $25
+ move $6, $ra
+ lw $25, %call16(__dlopen)($gp)
+ addiu $sp, $sp, -16
+ sw $ra, 12($sp)
+ jalr $25
+ nop
+ lw $ra, 12($sp)
+ jr $ra
+ addiu $sp, $sp, 16
diff --git a/src/ldso/mips64/dlopen.s b/src/ldso/mips64/dlopen.s
new file mode 100644
index 00000000..95c2b11c
--- /dev/null
+++ b/src/ldso/mips64/dlopen.s
@@ -0,0 +1,17 @@
+.set noreorder
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ lui $3, %hi(%neg(%gp_rel(dlopen)))
+ daddiu $3, $3, %lo(%neg(%gp_rel(dlopen)))
+ daddu $3, $3, $25
+ move $6, $ra
+ ld $25, %got_disp(__dlopen)($3)
+ daddiu $sp, $sp, -32
+ sd $ra, 24($sp)
+ jalr $25
+ nop
+ ld $ra, 24($sp)
+ jr $ra
+ daddiu $sp, $sp, 32
diff --git a/src/ldso/mipsn32/dlopen.s b/src/ldso/mipsn32/dlopen.s
new file mode 100644
index 00000000..cccd92a7
--- /dev/null
+++ b/src/ldso/mipsn32/dlopen.s
@@ -0,0 +1,17 @@
+.set noreorder
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ lui $3, %hi(%neg(%gp_rel(dlopen)))
+ addiu $3, $3, %lo(%neg(%gp_rel(dlopen)))
+ addu $3, $3, $25
+ move $6, $ra
+ lw $25, %got_disp(__dlopen)($3)
+ addiu $sp, $sp, -32
+ sd $ra, 16($sp)
+ jalr $25
+ nop
+ ld $ra, 16($sp)
+ jr $ra
+ addiu $sp, $sp, 32
diff --git a/src/ldso/or1k/dlopen.s b/src/ldso/or1k/dlopen.s
new file mode 100644
index 00000000..2e7ae870
--- /dev/null
+++ b/src/ldso/or1k/dlopen.s
@@ -0,0 +1,6 @@
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ l.j __dlopen
+ l.ori r5, r9, 0
diff --git a/src/ldso/powerpc/dlopen.s b/src/ldso/powerpc/dlopen.s
new file mode 100644
index 00000000..49d52a5f
--- /dev/null
+++ b/src/ldso/powerpc/dlopen.s
@@ -0,0 +1,8 @@
+ .text
+ .global dlopen
+ .hidden __dlopen
+ .type dlopen,@function
+dlopen:
+ mflr 5 # The return address is arg3.
+ b __dlopen
+ .size dlopen, .-dlopen
diff --git a/src/ldso/powerpc64/dlopen.s b/src/ldso/powerpc64/dlopen.s
new file mode 100644
index 00000000..3bd43fba
--- /dev/null
+++ b/src/ldso/powerpc64/dlopen.s
@@ -0,0 +1,11 @@
+ .text
+ .global dlopen
+ .hidden __dlopen
+ .type dlopen,@function
+dlopen:
+ addis 2, 12, .TOC.-dlopen@ha
+ addi 2, 2, .TOC.-dlopen@l
+ .localentry dlopen,.-dlopen
+ mflr 5 # The return address is arg3.
+ b __dlopen
+ .size dlopen, .-dlopen
diff --git a/src/ldso/riscv32/dlopen.s b/src/ldso/riscv32/dlopen.s
new file mode 100644
index 00000000..308d4e8d
--- /dev/null
+++ b/src/ldso/riscv32/dlopen.s
@@ -0,0 +1,6 @@
+.global dlopen
+.hidden __dlopen
+.type dlopen, %function
+dlopen:
+ mv a2, ra
+ tail __dlopen
diff --git a/src/ldso/riscv64/dlopen.s b/src/ldso/riscv64/dlopen.s
new file mode 100644
index 00000000..308d4e8d
--- /dev/null
+++ b/src/ldso/riscv64/dlopen.s
@@ -0,0 +1,6 @@
+.global dlopen
+.hidden __dlopen
+.type dlopen, %function
+dlopen:
+ mv a2, ra
+ tail __dlopen
diff --git a/src/ldso/s390x/dlopen.s b/src/ldso/s390x/dlopen.s
new file mode 100644
index 00000000..ff2bb284
--- /dev/null
+++ b/src/ldso/s390x/dlopen.s
@@ -0,0 +1,6 @@
+ .global dlopen
+ .hidden __dlopen
+ .type dlopen,@function
+dlopen:
+ lgr %r4, %r14
+ jg __dlopen
diff --git a/src/ldso/sh/dlopen.s b/src/ldso/sh/dlopen.s
new file mode 100644
index 00000000..349c71d8
--- /dev/null
+++ b/src/ldso/sh/dlopen.s
@@ -0,0 +1,11 @@
+.text
+.global dlopen
+.hidden __dlopen
+.type dlopen, @function
+dlopen:
+ mov.l L1, r0
+1: braf r0
+ sts pr, r6
+
+.align 2
+L1: .long __dlopen@...-(1b+4-.)
diff --git a/src/ldso/x32/dlopen.s b/src/ldso/x32/dlopen.s
new file mode 100644
index 00000000..8196ab54
--- /dev/null
+++ b/src/ldso/x32/dlopen.s
@@ -0,0 +1,7 @@
+.text
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ mov (%rsp),%rdx
+ jmp __dlopen
diff --git a/src/ldso/x86_64/dlopen.s b/src/ldso/x86_64/dlopen.s
new file mode 100644
index 00000000..8196ab54
--- /dev/null
+++ b/src/ldso/x86_64/dlopen.s
@@ -0,0 +1,7 @@
+.text
+.global dlopen
+.hidden __dlopen
+.type dlopen,@function
+dlopen:
+ mov (%rsp),%rdx
+ jmp __dlopen
---
base-commit: 1b76ff0767d01df72f692806ee5adee13c67ef88
change-id: 20251016-dlopen-use-rpath-of-caller-dso-e78fd9e573d0
Best regards,
--
Vivian "dramforever" Wang
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.