diff mbox series

[5/6] musl: make ldd work with multilib

Message ID 20261103231607.4021851-6-mark.yang@lge.com
State New
Headers show
Series musl: support multilib | expand

Commit Message

mark.yang Nov. 3, 2026, 11:16 p.m. UTC
From: "mark.yang" <mark.yang@lge.com>

Replace the /usr/bin/ldd link to libc.so with a script, and ship it in
its own ldd package.

The script and its packaging follow glibc:

- RTLDLIST holds the loader of every variant, built with
  oe.utils.all_multilib_tune_values() as in glibc-ld.inc. do_install
  substitutes it into the script, so both variants ship the same file.
- ldd uses the first installed loader in RTLDLIST with the same ELF
  class as the file.
- The package is named ldd, as in glibc-package.inc. RDEPENDS on ldd
  need no RPROVIDES. The oeqa runtime ldd test checks for this package
  name, so it now runs on musl.

glibc's ldd finds that loader by running each one with --verify. In
open_verify(), the loader compares e_ident[EI_CLASS] of the file with
its own class and exits with 1 when they differ.

The musl loader has no --verify. Without a check in the script, the
user has to run the loader that matches each program by hand:

  /lib/ld-musl-aarch64.so.1 --list app64
  /lib/ld-musl-armhf.so.1 --list app32

In a mixed image, /usr/bin holds programs of both classes, and the
file name does not show which.

The script therefore makes the same comparison as glibc. It reads
byte 4 (EI_CLASS) of the file and of each loader with dd:

  dd if=app64 bs=1 skip=4 count=1                      -> 2 (ELFCLASS64)
  dd if=app32 bs=1 skip=4 count=1                      -> 1 (ELFCLASS32)
  dd if=/lib/ld-musl-aarch64.so.1 bs=1 skip=4 count=1  -> 2 (ELFCLASS64)
  dd if=/lib/ld-musl-armhf.so.1 bs=1 skip=4 count=1    -> 1 (ELFCLASS32)

ldd then picks the aarch64 loader for app64 and the armhf loader for
app32. This gives the two commands above.

A loader's own header holds the class it was built for. glibc uses the
same value as the constant ELFW(CLASS).

The command follows Alpine. Its musl APKBUILD writes ldd as
'exec /lib/$LDSO --list "$@"'.

musl upstream also recommends this form over the argv[0] link.
Reference: https://www.openwall.com/lists/musl/2023/04/17/6

When no loader matches, as for a non-ELF file, the first installed
loader in RTLDLIST reports the error.

musl no longer provides ldd. As with glibc, an image gets it only
when something installs or depends on it.

Signed-off-by: mark.yang <mark.yang@lge.com>
---
 meta/recipes-core/musl/musl/ldd    | 18 ++++++++++++++++++
 meta/recipes-core/musl/musl_git.bb | 12 ++++++++++--
 2 files changed, 28 insertions(+), 2 deletions(-)
 create mode 100644 meta/recipes-core/musl/musl/ldd
diff mbox series

Patch

diff --git a/meta/recipes-core/musl/musl/ldd b/meta/recipes-core/musl/musl/ldd
new file mode 100644
index 0000000000..c24533cc95
--- /dev/null
+++ b/meta/recipes-core/musl/musl/ldd
@@ -0,0 +1,18 @@ 
+#!/bin/sh
+
+RTLDLIST="@RTLDLIST@"
+
+elfclass() {
+	dd if="$1" bs=1 skip=4 count=1 2>/dev/null
+}
+
+class=$(elfclass "$1")
+first=
+for rtld in $RTLDLIST; do
+	[ -x "$rtld" ] || continue
+	[ -n "$first" ] || first=$rtld
+	if [ "$(elfclass "$rtld")" = "$class" ]; then
+		exec "$rtld" --list "$@"
+	fi
+done
+exec "$first" --list "$@"
diff --git a/meta/recipes-core/musl/musl_git.bb b/meta/recipes-core/musl/musl_git.bb
index b8fef8990e..80c9bd9292 100644
--- a/meta/recipes-core/musl/musl_git.bb
+++ b/meta/recipes-core/musl/musl_git.bb
@@ -15,6 +15,7 @@  SRC_URI = "git://git.musl-libc.org/musl;branch=master \
            file://0002-ldso-Use-syslibdir-and-libdir-as-default-pathes-to-l.patch \
            file://0003-tools-version.sh-fall-back-to-VERSION-when-git-descr.patch \
            file://0004-configure-use-ffp-exception-behavior-maytrap-when-su.patch \
+           file://ldd \
           "
 
 PROVIDES += "virtual/libc virtual/libiconv virtual/libintl virtual/crypt"
@@ -28,6 +29,9 @@  DEPENDS = "virtual/cross-binutils \
           "
 GLIBC_LDSO = "${@get_glibc_loader(d)}"
 MUSL_LDSO_ARCH = "${@get_musl_loader_arch(d)}"
+MUSL_GETLOADER = "${@get_musl_loader(d)}"
+RTLDLIST = "${@oe.utils.all_multilib_tune_values(d, 'MUSL_GETLOADER')}"
+RTLDLIST[vardepvalue] = "${RTLDLIST}"
 
 export CROSS_COMPILE = "${TARGET_PREFIX}"
 
@@ -68,7 +72,8 @@  do_install() {
         echo "${base_libdir}" > ${D}${sysconfdir}/ld-musl-${MUSL_LDSO_ARCH}.path
         echo "${libdir}" >> ${D}${sysconfdir}/ld-musl-${MUSL_LDSO_ARCH}.path
 	rm -f ${D}${bindir}/ldd ${D}${GLIBC_LDSO}
-	ln -rs ${D}${libdir}/libc.so ${D}${bindir}/ldd
+	install -m 0755 ${UNPACKDIR}/ldd ${D}${bindir}/ldd
+	sed -i -e 's#@RTLDLIST@#${RTLDLIST}#' ${D}${bindir}/ldd
 	musl_multilib_bits
 }
 
@@ -78,6 +83,9 @@  musl_multilib_bits () {
 	done
 }
 
+PACKAGES =+ "ldd"
+
+FILES:ldd = "${bindir}/ldd"
 FILES:${PN} += "${nonarch_base_libdir}/ld-musl-${MUSL_LDSO_ARCH}.so.1 ${sysconfdir}/ld-musl-${MUSL_LDSO_ARCH}.path"
 FILES:${PN}-staticdev = "${libdir}/libc.a"
 FILES:${PN}-dev =+ "${libdir}/libcrypt.a ${libdir}/libdl.a ${libdir}/libm.a \
@@ -87,7 +95,7 @@  FILES:${PN}-dev =+ "${libdir}/libcrypt.a ${libdir}/libdl.a ${libdir}/libm.a \
 
 RDEPENDS:${PN}-dev += "linux-libc-headers-dev bsd-headers-dev libssp-nonshared-staticdev"
 RPROVIDES:${PN}-dev += "libc-dev virtual-libc-dev"
-RPROVIDES:${PN} += "ldd rtld(GNU_HASH)"
+RPROVIDES:${PN} += "rtld(GNU_HASH)"
 
 LEAD_SONAME = "libc.so"
 INSANE_SKIP:${PN}-dev = "staticdev"