![]() |
|
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.