diff --git a/build.sh b/build.sh index 03ff4e4..314a59f 100755 --- a/build.sh +++ b/build.sh @@ -4,7 +4,7 @@ # # This script produces a self-contained, bootable Linux image targeting the Arm # MPS2-AN386 FPGA platform (Cortex-M4, no MMU, Thumb-2 only). -# It builds a first-pass GCC cross-compiler (C only), shared FDPIC uClibc-ng, +# It builds a first-pass GCC cross-compiler (C only), a shared FDPIC libc, # BusyBox for a minimal userspace, and a Linux kernel with embedded initramfs. set -e @@ -18,6 +18,7 @@ FLAVOR=cortexm-fdpic BINUTILS_VERSION=2.46.0 GCC_VERSION=16.1.0 UCLIBC_NG_VERSION=1.0.57 +MUSL_VERSION=1.2.5 BUSYBOX_VERSION=1.37.0 LINUX_VERSION=7.0 @@ -31,6 +32,7 @@ GCC_URL=https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.xz # back below to keep configs/uClibc-ng-*.config and the rest of this # script unchanged). UCLIBC_NG_URL=https://github.com/wbx-github/uclibc-ng/archive/refs/tags/v${UCLIBC_NG_VERSION}.tar.gz +MUSL_URL=https://musl.libc.org/releases/musl-${MUSL_VERSION}.tar.gz BUSYBOX_URL=https://busybox.net/downloads/busybox-${BUSYBOX_VERSION}.tar.bz2 LINUX_URL=https://www.kernel.org/pub/linux/kernel/v7.x/linux-${LINUX_VERSION}.tar.xz @@ -61,6 +63,45 @@ PGO_BASE_CONFIG_FRAGMENT=${PGO_BASE_CONFIG_FRAGMENT:-${ROOTDIR}/configs/kernel-p # Keep the default empty; production defaults to no kernel LTO because # the current pruned image is smaller without it. KERNEL_LTO_EXTRA_CFLAGS=${KERNEL_LTO_EXTRA_CFLAGS:-} +LIBC_IMPL_EXPLICIT=0 +if [ "${LIBC_IMPL+x}" = x ]; then + LIBC_IMPL_EXPLICIT=1 +fi +EXPERIMENTAL_MUSL_DEFAULT=${EXPERIMENTAL_MUSL_DEFAULT:-0} +if [ "${LIBC_IMPL_EXPLICIT}" = "0" ]; then + if [ "${EXPERIMENTAL_MUSL_DEFAULT}" = "1" ]; then + LIBC_IMPL=musl + else + LIBC_IMPL=uclibc-ng + fi +fi +# Closest musl-side matches for the size-oriented uClibc-ng config: +# simple allocator, section-friendly codegen, GNU hash-only dynamic +# linker metadata, no legacy time32 compatibility shims, and a +# BusyBox-only source set that drops unused subsystems plus most of +# musl's locale/multibyte/wide-char machinery in favor of tiny +# ASCII/C-locale replacements. +MUSL_MALLOC_DIR=${MUSL_MALLOC_DIR:-oldmalloc} +MUSL_DISABLE_COMPAT_TIME32=${MUSL_DISABLE_COMPAT_TIME32:-1} +# GCC 15 on this target shrinks musl materially with -Oz and +# -fno-semantic-interposition. The latter is safe for this BusyBox-only +# shared-libc profile and reduces internal PIC call overhead/size by +# letting the compiler assume musl's own global definitions are final. +MUSL_EXTRA_CFLAGS=${MUSL_EXTRA_CFLAGS:--Oz -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -fno-semantic-interposition} +MUSL_EXTRA_LDFLAGS=${MUSL_EXTRA_LDFLAGS:--Wl,--gc-sections -Wl,--hash-style=gnu} +MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL=${MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL:-1} +MUSL_BUSYBOX_ONLY_NO_TZFILE=${MUSL_BUSYBOX_ONLY_NO_TZFILE:-1} +# Experimental: generate a BusyBox-derived musl export map and relink +# libc against it. This is currently useful as a size-analysis tool, but +# the pruned-export FDPIC runtime is not yet proven bootable enough to be +# the default build path on this target. +MUSL_BUSYBOX_ONLY_EXPORT_MAP=${MUSL_BUSYBOX_ONLY_EXPORT_MAP:-0} +MUSL_BUSYBOX_EXPORT_MAP_PATH=${MUSL_BUSYBOX_EXPORT_MAP_PATH:-${STATE_DIR}/musl-busybox-exports.map} +MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES=${MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES:-2} +MUSL_PRUNE_UNUSED_MATH=${MUSL_PRUNE_UNUSED_MATH:-1} +MUSL_KEEP_MATH_SRCS=${MUSL_KEEP_MATH_SRCS:-copysign.c copysignl.c fabs.c fabsl.c fmod.c fmodl.c frexp.c frexpl.c scalbn.c scalbnf.c scalbnl.c} +MUSL_OMIT_SRCS_GLOBS=${MUSL_OMIT_SRCS_GLOBS:-./src/aio/*.c ./src/complex/*.c ./src/crypt/*.c ./src/mq/*.c ./src/locale/*.c ./src/multibyte/*.c ./src/ctype/isw*.c ./src/ctype/tow*.c ./src/ctype/wc*.c ./src/misc/wordexp.c ./src/misc/nftw.c ./src/legacy/ftw.c ./src/time/__map_file.c ./src/regex/regcomp.c ./src/regex/regerror.c ./src/regex/regexec.c ./src/regex/tre-mem.c ./src/stdlib/atof.c ./src/stdlib/strtod.c ./src/stdlib/wcstod.c} +BUSYBOX_ONLY_NO_PRINTF_FLOAT=${BUSYBOX_ONLY_NO_PRINTF_FLOAT:-1} NCPU=$(grep -c processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1) MAKE_JOBS=${MAKE_JOBS:-${NCPU}} @@ -75,14 +116,79 @@ mkdir -p "${LOGDIR}" "${STATE_DIR}" CHECKSUM_binutils="binutils-${BINUTILS_VERSION}.tar.xz=d75a94f4d73e7a4086f7513e67e439e8fcdcbb726ffe63f4661744e6256b2cf2" CHECKSUM_gcc="gcc-${GCC_VERSION}.tar.xz=50efb4d94c3397aff3b0d61a5abd748b4dd31d9d3f2ab7be05b171d36a510f79" CHECKSUM_uclibc="v${UCLIBC_NG_VERSION}.tar.gz=f49704e0affc75fde9ee4e870c20e53c1d807eca2a4683377b359b8361e84312" +CHECKSUM_musl="musl-${MUSL_VERSION}.tar.gz=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4" CHECKSUM_busybox="busybox-${BUSYBOX_VERSION}.tar.bz2=3311dff32e746499f4df0d5df04d7eb396382d7e108bb9250e7b519b837043a4" CHECKSUM_linux="linux-${LINUX_VERSION}.tar.xz=bb7f6d80b387c757b7d14bb93028fcb90f793c5c0d367736ee815a100b3891f0" +assert_supported_libc() { + case "${LIBC_IMPL}" in + uclibc-ng) + return 0 + ;; + musl) + return 0 + ;; + *) + echo "ERROR: unsupported LIBC_IMPL='${LIBC_IMPL}' (expected 'uclibc-ng' or 'musl')" >&2 + exit 1 + ;; + esac +} + +libc_config_glob() { + case "${LIBC_IMPL}" in + uclibc-ng) echo "configs/uClibc-ng-*" ;; + musl) echo "configs/musl-*" ;; + *) + echo "ERROR: unsupported LIBC_IMPL='${LIBC_IMPL}' (expected 'uclibc-ng' or 'musl')" >&2 + exit 1 + ;; + esac +} + toolchain_fingerprint() { + LIBC_CONFIGS=$(libc_config_glob) { sha256sum build.sh sha256sum patches/0001-* 2>/dev/null || true - sha256sum configs/uClibc-ng-* 2>/dev/null || true + sha256sum ${LIBC_CONFIGS} 2>/dev/null || true + printf 'EXPERIMENTAL_MUSL_DEFAULT=%s\n' "${EXPERIMENTAL_MUSL_DEFAULT}" + printf 'LIBC_IMPL=%s\n' "${LIBC_IMPL}" + if [ "${LIBC_IMPL}" = "musl" ]; then + sha256sum \ + patches/0024-musl-* \ + patches/0025-musl-* \ + patches/0026-musl-* \ + patches/0027-musl-* \ + patches/0028-musl-* \ + patches/0029-musl-* \ + patches/0030-musl-* \ + patches/0031-musl-* \ + patches/0033-musl-* \ + patches/0034-musl-* \ + patches/0035-musl-* \ + patches/0036-musl-* \ + patches/0037-musl-* \ + patches/0038-musl-* \ + patches/0039-musl-* \ + patches/0040-musl-* \ + support/arm-fdpic-crtreloc.c \ + 2>/dev/null || true + printf 'MUSL_MALLOC_DIR=%s\n' "${MUSL_MALLOC_DIR}" + printf 'MUSL_DISABLE_COMPAT_TIME32=%s\n' "${MUSL_DISABLE_COMPAT_TIME32}" + printf 'MUSL_EXTRA_CFLAGS=%s\n' "${MUSL_EXTRA_CFLAGS}" + printf 'MUSL_EXTRA_LDFLAGS=%s\n' "${MUSL_EXTRA_LDFLAGS}" + printf 'MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL=%s\n' "${MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL}" + printf 'MUSL_BUSYBOX_ONLY_NO_TZFILE=%s\n' "${MUSL_BUSYBOX_ONLY_NO_TZFILE}" + printf 'MUSL_BUSYBOX_ONLY_EXPORT_MAP=%s\n' "${MUSL_BUSYBOX_ONLY_EXPORT_MAP}" + printf 'MUSL_PRUNE_UNUSED_MATH=%s\n' "${MUSL_PRUNE_UNUSED_MATH}" + printf 'MUSL_KEEP_MATH_SRCS=%s\n' "${MUSL_KEEP_MATH_SRCS}" + printf 'MUSL_OMIT_SRCS_GLOBS=%s\n' "${MUSL_OMIT_SRCS_GLOBS}" + printf 'BUSYBOX_ONLY_NO_PRINTF_FLOAT=%s\n' "${BUSYBOX_ONLY_NO_PRINTF_FLOAT}" + if [ -f "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" ]; then + sha256sum "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" + fi + fi } | sha256sum | cut -d' ' -f1 } @@ -109,12 +215,16 @@ image_fingerprint() { } | sha256sum | cut -d' ' -f1 } -TOOLCHAIN_FP=$(toolchain_fingerprint) -IMAGE_FP=$(image_fingerprint "${TOOLCHAIN_FP}") +refresh_build_fingerprints() { + TOOLCHAIN_FP=$(toolchain_fingerprint) + IMAGE_FP=$(image_fingerprint "${TOOLCHAIN_FP}") +} + +refresh_build_fingerprints stage_fingerprint() { case "$1" in - binutils|gcc|linux_headers|uClibc) + binutils|gcc|linux_headers|libc) printf '%s' "${TOOLCHAIN_FP}" ;; *) printf '%s' "${IMAGE_FP}" ;; @@ -180,7 +290,7 @@ stage_verify_linux_headers() { [ -f "${TOOLCHAIN}/${TARGET}/include/linux/types.h" ] } -stage_verify_uClibc() { +stage_verify_libc() { [ -f "${TOOLCHAIN}/${TARGET}/lib/libc.a" ] || [ -f "${TOOLCHAIN}/${TARGET}/lib/libc.so" ] } @@ -198,12 +308,13 @@ stage_verify_finalize_rootfs() { INTERP=$(LC_ALL=C "${READELF}" -l "${ROOTFS}/bin/busybox" 2>/dev/null | sed -n 's/.*Requesting program interpreter: \(.*\)]/\1/p') [ -z "${INTERP}" ] && return 0 - [ -e "${ROOTFS}${INTERP}" ] || return 1 + [ -e "${ROOTFS}${INTERP}" ] || [ -L "${ROOTFS}${INTERP}" ] || return 1 _needed_libs=$(LC_ALL=C "${READELF}" -d "${ROOTFS}/bin/busybox" 2>/dev/null | sed -n 's/.*Shared library: \[\(.*\)\]/\1/p') for needed in ${_needed_libs}; do - [ -e "${ROOTFS}/lib/${needed}" ] || [ -e "${ROOTFS}/usr/lib/${needed}" ] || return 1 + [ -e "${ROOTFS}/lib/${needed}" ] || [ -L "${ROOTFS}/lib/${needed}" ] || + [ -e "${ROOTFS}/usr/lib/${needed}" ] || [ -L "${ROOTFS}/usr/lib/${needed}" ] || return 1 done } @@ -251,7 +362,7 @@ stage_clean() { binutils) rm -rf "binutils-${BINUTILS_VERSION}" ;; gcc) rm -rf "gcc-${GCC_VERSION}" ;; linux_headers) rm -rf "linux-${LINUX_VERSION}" ;; # shared with linux; both extract fresh - uClibc) rm -rf "uClibc-ng-${UCLIBC_NG_VERSION}" ;; + libc) rm -rf "uClibc-ng-${UCLIBC_NG_VERSION}" "musl-${MUSL_VERSION}" ;; busybox) rm -rf "busybox-${BUSYBOX_VERSION}" "${ROOTFS}" ;; finalize_rootfs) ;; # idempotent; overwrites its outputs linux) rm -rf "linux-${LINUX_VERSION}" ;; @@ -427,7 +538,7 @@ build_linux_headers() { cd ../ } -build_uClibc() { +build_uclibc_ng() { echo "BUILD: building uClibc-${UCLIBC_NG_VERSION}" fetch_file "${UCLIBC_NG_URL}" "${CHECKSUM_uclibc}" @@ -463,6 +574,307 @@ build_uClibc() { cd ../ } +build_musl() { + echo "BUILD: building musl-${MUSL_VERSION}" + fetch_file "${MUSL_URL}" "${CHECKSUM_musl}" + + extract_source "musl-${MUSL_VERSION}.tar.gz" "musl-${MUSL_VERSION}" -xzf + cd musl-${MUSL_VERSION} + + apply_patch_once ../patches/0024-musl-arm-fdpic-dynamic-linking.patch + apply_patch_once ../patches/0025-musl-tiny-iconv.patch + apply_patch_once ../patches/0026-musl-allow-omitting-source-globs.patch + apply_patch_once ../patches/0027-musl-busybox-only-c-locale-and-ascii-multibyte.patch + apply_patch_once ../patches/0028-musl-busybox-only-c-locale.patch + apply_patch_once ../patches/0029-musl-busybox-only-disable-runtime-dlfcn.patch + apply_patch_once ../patches/0030-musl-busybox-only-minimal-dlfcn-stubs.patch + apply_patch_once ../patches/0031-musl-busybox-only-no-tzfile.patch + apply_patch_once ../patches/0033-musl-fdpic-dlstart-direct-dls2.patch + apply_patch_once ../patches/0034-musl-arm-fdpic-soft-tp.patch + apply_patch_once ../patches/0035-musl-fdpic-local-funcdesc-got.patch + apply_patch_once ../patches/0036-musl-fdpic-dlstart-handle-rel.patch + apply_patch_once ../patches/0037-musl-fdpic-init-array-fpaddr.patch + apply_patch_once ../patches/0038-musl-fdpic-runtime-relative-laddr.patch + apply_patch_once ../patches/0039-musl-arm-fdpic-xip-aware-loadmap-and-textrel.patch + apply_patch_once ../patches/0040-musl-fdpic-laddr-idempotent.patch + # musl's ARM TLS fast paths assume CP15/kuser helper conventions that + # do not hold on this Cortex-M FDPIC target. Force direct TP reads + # through the working Thumb syscall ABI instead of function-pointer + # or CP15-based helpers. + cat > arch/arm/pthread_arch.h <<'EOF' +#ifdef __FDPIC__ +static inline uintptr_t __get_tp() +{ + extern hidden uintptr_t __aeabi_read_tp(void); + return __aeabi_read_tp(); +} +#elif ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ + || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 + +static inline uintptr_t __get_tp() +{ + uintptr_t tp; + __asm__ ( "mrc p15,0,%0,c13,c0,3" : "=r"(tp) ); + return tp; +} + +#else + +#if __ARM_ARCH_4__ || __ARM_ARCH_4T__ || __ARM_ARCH == 4 +#define BLX "mov lr,pc\n\tbx" +#else +#define BLX "blx" +#endif + +static inline uintptr_t __get_tp() +{ + extern hidden uintptr_t __a_gettp_ptr; + register uintptr_t tp __asm__("r0"); + __asm__ ( BLX " %1" : "=r"(tp) : "r"(__a_gettp_ptr) : "cc", "lr" ); + return tp; +} + +#endif + +#define TLS_ABOVE_TP +#define GAP_ABOVE_TP 8 + +#define MC_PC arm_pc + +#ifdef __FDPIC__ +#define MC_GOT arm_r9 +#define CANCEL_GOT (*(uintptr_t *)((char *)__syscall_cp_asm+sizeof(uintptr_t))) +#endif +EOF + cat > src/thread/arm/__aeabi_read_tp.s <<'EOF' +.syntax unified +.global __aeabi_read_tp +.type __aeabi_read_tp,%function +__aeabi_read_tp: +#if __FDPIC__ + push {r7} + mov r7, #0x0f0000 + orr r7, r7, #6 + svc #0 + pop {r7} + bx lr +#else + ldr r0,1f + add r0,r0,pc + ldr r0,[r0] +2: bx r0 + .align 2 +1: .word __a_gettp_ptr - 2b +#endif +EOF + cat > src/ldso/arm/tlsdesc.S <<'EOF' +.syntax unified + +.text +.global __tlsdesc_static +.hidden __tlsdesc_static +.type __tlsdesc_static,%function +__tlsdesc_static: + ldr r0,[r0] + bx lr + +.global __tlsdesc_dynamic +.hidden __tlsdesc_dynamic +.type __tlsdesc_dynamic,%function +__tlsdesc_dynamic: + push {r2,r3,ip,lr} + ldr r1,[r0] + ldr r2,[r1,#4] + ldr r1,[r1] + +#if __FDPIC__ + push {r7} + mov r7, #0x0f0000 + orr r7, r7, #6 + svc #0 + pop {r7} +#elif ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ + || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 + mrc p15,0,r0,c13,c0,3 +#else + ldr r0,1f + add r0,r0,pc + ldr r0,[r0] +2: +#if __ARM_ARCH >= 5 + blx r0 +#else +#if __thumb__ + add lr,pc,#1 +#else + mov lr,pc +#endif + bx r0 +#endif +#endif + ldr r3,[r0,#-4] + ldr ip,[r3,r1,LSL #2] + sub r0,ip,r0 + add r0,r0,r2 +#if __ARM_ARCH >= 5 + pop {r2,r3,ip,pc} +#else + pop {r2,r3,ip,lr} + bx lr +#endif + +#if __FDPIC__ || (((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ + || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7) +#else + .align 2 +1: .word __a_gettp_ptr - 2b +#endif +EOF + MUSL_EFFECTIVE_CFLAGS=${MUSL_EXTRA_CFLAGS} + MUSL_EFFECTIVE_LDFLAGS=${MUSL_EXTRA_LDFLAGS} + if [ "${MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL}" = "1" ]; then + MUSL_EFFECTIVE_CFLAGS="${MUSL_EFFECTIVE_CFLAGS} -DMUSL_BUSYBOX_ONLY_NO_RUNTIME_DL=1" + fi + if [ "${MUSL_BUSYBOX_ONLY_NO_TZFILE}" = "1" ]; then + MUSL_EFFECTIVE_CFLAGS="${MUSL_EFFECTIVE_CFLAGS} -DMUSL_BUSYBOX_ONLY_NO_TZFILE=1" + fi + if [ "${MUSL_BUSYBOX_ONLY_EXPORT_MAP}" = "1" ] && + [ "${MUSL_BUSYBOX_EXPORT_MAP_PASS:-0}" -gt 0 ] && + [ -f "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" ]; then + MUSL_EFFECTIVE_LDFLAGS="${MUSL_EFFECTIVE_LDFLAGS} -Wl,--version-script=${MUSL_BUSYBOX_EXPORT_MAP_PATH}" + fi + MUSL_EFFECTIVE_OMIT_SRCS_GLOBS=${MUSL_OMIT_SRCS_GLOBS} + if [ "${MUSL_PRUNE_UNUSED_MATH}" = "1" ]; then + for math_src in src/math/*.c; do + math_keep=0 + for keep_src in ${MUSL_KEEP_MATH_SRCS}; do + if [ "$(basename "${math_src}")" = "${keep_src}" ]; then + math_keep=1 + break + fi + done + if [ "${math_keep}" = "0" ]; then + MUSL_EFFECTIVE_OMIT_SRCS_GLOBS="${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS} ./${math_src}" + fi + done + for math_src in src/math/arm/*.c; do + MUSL_EFFECTIVE_OMIT_SRCS_GLOBS="${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS} ./${math_src}" + done + fi + + run_logged "configure" env \ + CC=${TOOLCHAIN}/bin/${TARGET}-gcc \ + AR=${TOOLCHAIN}/bin/${TARGET}-ar \ + RANLIB=${TOOLCHAIN}/bin/${TARGET}-ranlib \ + ./configure --prefix=/ --syslibdir=/lib + if [ "${MUSL_DISABLE_COMPAT_TIME32}" = "1" ]; then + # This build only targets our bundled BusyBox on a modern kernel, + # so we can drop the 32-bit time ABI compatibility shims to save + # space in the shared libc. + run_logged "build" make -j${MAKE_JOBS} \ + MALLOC_DIR=${MUSL_MALLOC_DIR} \ + STARTFILE_CRT=rcrt1.o \ + LDSO_ABI_SUFFIX=-fdpic \ + COMPAT_SRC_DIRS= \ + "OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \ + "CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \ + "LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}" + else + run_logged "build" make -j${MAKE_JOBS} \ + MALLOC_DIR=${MUSL_MALLOC_DIR} \ + STARTFILE_CRT=rcrt1.o \ + LDSO_ABI_SUFFIX=-fdpic \ + "OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \ + "CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \ + "LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}" + fi + + MUSL_KERNEL_HEADERS_BACKUP=${ROOTDIR}/.musl-kernel-headers + rm -rf "${MUSL_KERNEL_HEADERS_BACKUP}" + mkdir -p "${MUSL_KERNEL_HEADERS_BACKUP}" + for hdr_dir in asm asm-generic drm linux misc mtd rdma scsi sound video xen; do + [ -e "${TOOLCHAIN}/${TARGET}/include/${hdr_dir}" ] || continue + cp -a "${TOOLCHAIN}/${TARGET}/include/${hdr_dir}" "${MUSL_KERNEL_HEADERS_BACKUP}/" + done + + rm -rf "${TOOLCHAIN}/${TARGET}/lib" + rm -rf "${TOOLCHAIN}/${TARGET}/include" + if [ "${MUSL_DISABLE_COMPAT_TIME32}" = "1" ]; then + run_logged "install" make \ + MALLOC_DIR=${MUSL_MALLOC_DIR} \ + STARTFILE_CRT=rcrt1.o \ + LDSO_ABI_SUFFIX=-fdpic \ + COMPAT_SRC_DIRS= \ + "OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \ + "CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \ + "LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}" \ + install DESTDIR="${TOOLCHAIN}/${TARGET}" + else + run_logged "install" make \ + MALLOC_DIR=${MUSL_MALLOC_DIR} \ + STARTFILE_CRT=rcrt1.o \ + LDSO_ABI_SUFFIX=-fdpic \ + "OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \ + "CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \ + "LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}" \ + install DESTDIR="${TOOLCHAIN}/${TARGET}" + fi + for hdr_dir in asm asm-generic drm linux misc mtd rdma scsi sound video xen; do + [ -e "${MUSL_KERNEL_HEADERS_BACKUP}/${hdr_dir}" ] || continue + cp -a "${MUSL_KERNEL_HEADERS_BACKUP}/${hdr_dir}" "${TOOLCHAIN}/${TARGET}/include/" + done + rm -rf "${MUSL_KERNEL_HEADERS_BACKUP}" + + # GCC's arm-uclinuxfdpiceabi FDPIC PIE specs expect musl's shared + # startup object plus a real __self_reloc implementation. Keep + # musl's Scrt1.o and provide an ARM FDPIC crtreloc.o instead of a + # placeholder. + cp lib/Scrt1.o "${TOOLCHAIN}/${TARGET}/lib/Scrt1.o" + ln -sf /lib/libc.so "${TOOLCHAIN}/${TARGET}/lib/ld-musl-arm-fdpic.so.1" + run_logged "build crtreloc" \ + "${TOOLCHAIN}/bin/${TARGET}-gcc" -c -fPIE \ + -I"${TOOLCHAIN}/${TARGET}/include" \ + "${ROOTDIR}/support/arm-fdpic-crtreloc.c" \ + -o "${TOOLCHAIN}/${TARGET}/lib/crtreloc.o" + cd ../ +} + +build_libc() { + assert_supported_libc + + case "${LIBC_IMPL}" in + uclibc-ng) + build_uclibc_ng + ;; + musl) + build_musl + ;; + esac +} + +refresh_musl_busybox_export_map() { + MAP_TMP=${STATE_DIR}/musl-busybox-exports.map.new + + [ "${LIBC_IMPL}" = "musl" ] || return 0 + [ "${MUSL_BUSYBOX_ONLY_EXPORT_MAP}" = "1" ] || return 0 + [ -x "${ROOTDIR}/scripts/generate-musl-export-map.sh" ] || return 0 + [ -f "${ROOTFS}/bin/busybox" ] || return 0 + + "${ROOTDIR}/scripts/generate-musl-export-map.sh" \ + "${ROOTFS}/bin/busybox" \ + "${TOOLCHAIN}/${TARGET}/lib/libc.so" \ + "${MAP_TMP}" + + if [ -f "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" ] && \ + cmp -s "${MAP_TMP}" "${MUSL_BUSYBOX_EXPORT_MAP_PATH}"; then + rm -f "${MAP_TMP}" + return 0 + fi + + mv "${MAP_TMP}" "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" + MUSL_BUSYBOX_EXPORT_MAP_UPDATED=1 +} + build_busybox() { echo "BUILD: building busybox-${BUSYBOX_VERSION}" fetch_file "${BUSYBOX_URL}" "${CHECKSUM_busybox}" @@ -470,13 +882,32 @@ build_busybox() { extract_source "busybox-${BUSYBOX_VERSION}.tar.bz2" "busybox-${BUSYBOX_VERSION}" -xjf cp configs/busybox-${BUSYBOX_VERSION}.config busybox-${BUSYBOX_VERSION}/.config cd busybox-${BUSYBOX_VERSION} + if [ "${LIBC_IMPL}" = "musl" ]; then + apply_patch_once ../patches/0032-busybox-only-disable-float-printf.patch + fi sed -i 's/# CONFIG_NOMMU is not set/CONFIG_NOMMU=y/' .config sed -i 's/# CONFIG_PIE is not set/CONFIG_PIE=y/' .config - sed -i "s|CONFIG_EXTRA_CFLAGS=\"\"|CONFIG_EXTRA_CFLAGS=\"--sysroot=${TOOLCHAIN}/${TARGET} -mthumb -march=armv7e-m -ffunction-sections -fdata-sections -fipa-icf -Os\"|" .config + case "${LIBC_IMPL}" in + uclibc-ng) + BUSYBOX_EXTRA_CFLAGS="--sysroot=${TOOLCHAIN}/${TARGET} -mthumb -march=armv7e-m -ffunction-sections -fdata-sections -fipa-icf -Os" + BUSYBOX_EXTRA_LDFLAGS="-Wl,--gc-sections" + BUSYBOX_EXTRA_LDLIBS="" + ;; + musl) + BUSYBOX_EXTRA_CFLAGS="--sysroot=${TOOLCHAIN}/${TARGET} -isystem ${TOOLCHAIN}/${TARGET}/include -mthumb -march=armv7e-m -ffunction-sections -fdata-sections -fipa-icf -Os" + if [ "${BUSYBOX_ONLY_NO_PRINTF_FLOAT}" = "1" ]; then + BUSYBOX_EXTRA_CFLAGS="${BUSYBOX_EXTRA_CFLAGS} -DBUSYBOX_ONLY_NO_PRINTF_FLOAT=1" + fi + BUSYBOX_EXTRA_LDFLAGS="-Wl,--gc-sections -Wl,-dynamic-linker,/lib/ld-musl-arm-fdpic.so.1 -Wl,-rpath-link,${TOOLCHAIN}/${TARGET}/lib -L${TOOLCHAIN}/${TARGET}/lib -B${TOOLCHAIN}/${TARGET}/lib" + BUSYBOX_EXTRA_LDLIBS="" + ;; + esac + sed -i "s|CONFIG_EXTRA_CFLAGS=\"\"|CONFIG_EXTRA_CFLAGS=\"${BUSYBOX_EXTRA_CFLAGS}\"|" .config # With FDPIC PIE userspace, gc-sections strips dead ELF sections before # the final link while preserving shared-library dynamic linking. - sed -i 's/CONFIG_EXTRA_LDFLAGS=""/CONFIG_EXTRA_LDFLAGS="-Wl,--gc-sections"/' .config + sed -i "s|CONFIG_EXTRA_LDFLAGS=\"\"|CONFIG_EXTRA_LDFLAGS=\"${BUSYBOX_EXTRA_LDFLAGS}\"|" .config + sed -i "s|CONFIG_EXTRA_LDLIBS=\"\"|CONFIG_EXTRA_LDLIBS=\"${BUSYBOX_EXTRA_LDLIBS}\"|" .config # Reinstall into a clean rootfs so disabled applets do not leave stale links. rm -rf "${ROOTFS}" @@ -484,6 +915,25 @@ build_busybox() { run_logged "oldconfig" make oldconfig run_logged "build and install" make -j${MAKE_JOBS} CROSS_COMPILE=${TARGET}- CONFIG_PREFIX=${ROOTFS} install SKIP_STRIP=y cd ../ + + MUSL_BUSYBOX_EXPORT_MAP_UPDATED=0 + refresh_musl_busybox_export_map + if [ "${MUSL_BUSYBOX_EXPORT_MAP_UPDATED}" = "1" ]; then + MUSL_BUSYBOX_EXPORT_MAP_PASS=${MUSL_BUSYBOX_EXPORT_MAP_PASS:-0} + MUSL_BUSYBOX_EXPORT_MAP_PASS=$((MUSL_BUSYBOX_EXPORT_MAP_PASS + 1)) + if [ "${MUSL_BUSYBOX_EXPORT_MAP_PASS}" -gt "${MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES}" ]; then + echo "ERROR: musl BusyBox export map did not converge after ${MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES} passes" >&2 + exit 1 + fi + + echo "BUILD: musl export map refreshed from BusyBox (pass ${MUSL_BUSYBOX_EXPORT_MAP_PASS})" + refresh_build_fingerprints + rm -rf "musl-${MUSL_VERSION}" "busybox-${BUSYBOX_VERSION}" "${ROOTFS}" + build_musl + build_busybox + mark_stage_complete libc + return 0 + fi } copy_runtime_src() { @@ -504,9 +954,14 @@ copy_runtime_src() { rel=${SRC#${TOOLCHAIN}/${TARGET}/} dst_dir=${ROOTFS}/$(dirname "${rel}") + dst=${dst_dir}/$(basename "${SRC}") mkdir -p "${dst_dir}" cp -a "${SRC}" "${dst_dir}/" + if [ ! -L "${dst}" ] && [ -x "${TOOLCHAIN}/bin/${TARGET}-strip" ]; then + "${TOOLCHAIN}/bin/${TARGET}-strip" --strip-unneeded "${dst}" >/dev/null 2>&1 || true + fi + if [ -L "${SRC}" ]; then TARGET_NAME=$(readlink "${SRC}") case "${TARGET_NAME}" in @@ -536,7 +991,7 @@ copy_runtime_entry() { NAME=$1 for libdir in "${TOOLCHAIN}/${TARGET}/lib" "${TOOLCHAIN}/${TARGET}/usr/lib"; do SRC=${libdir}/${NAME} - [ -e "${SRC}" ] || continue + [ -e "${SRC}" ] || [ -L "${SRC}" ] || continue copy_runtime_src "${SRC}" return 0 done @@ -2307,6 +2762,7 @@ if [ "${1:-}" = "clean" ]; then rm -rf gcc-${GCC_VERSION} rm -rf linux-${LINUX_VERSION} rm -rf uClibc-ng-${UCLIBC_NG_VERSION} + rm -rf musl-${MUSL_VERSION} rm -rf busybox-${BUSYBOX_VERSION} rm -rf bootwrapper rm -rf "${TOOLCHAIN}" @@ -2316,7 +2772,7 @@ if [ "${1:-}" = "clean" ]; then exit 0 fi -DEFAULT_STAGES="binutils gcc linux_headers uClibc busybox finalize_rootfs linux bootwrapper" +DEFAULT_STAGES="binutils gcc linux_headers libc busybox finalize_rootfs linux bootwrapper" ALL_STAGES="${DEFAULT_STAGES} kernel_pgo_cycle kernel_syscall_prune_cycle kernel_lto_sweep" if [ "$#" = 0 ]; then @@ -2325,7 +2781,10 @@ else STAGES="" for arg in "$@"; do case "${arg}" in - binutils | gcc | linux_headers | uClibc | busybox | finalize_rootfs | linux | bootwrapper | kernel_pgo_cycle | kernel_syscall_prune_cycle | kernel_lto_sweep) + uClibc) + STAGES="${STAGES} libc" + ;; + binutils | gcc | linux_headers | libc | busybox | finalize_rootfs | linux | bootwrapper | kernel_pgo_cycle | kernel_syscall_prune_cycle | kernel_lto_sweep) STAGES="${STAGES} ${arg}" ;; *) @@ -2334,12 +2793,20 @@ else echo "" echo "default stages: ${DEFAULT_STAGES}" echo "all stages: ${ALL_STAGES}" + echo "default libc: ${LIBC_IMPL}" + echo "experimental musl default gate: EXPERIMENTAL_MUSL_DEFAULT=1" exit 1 ;; esac done fi +if [ "${EXPERIMENTAL_MUSL_DEFAULT}" = "1" ] && [ "${LIBC_IMPL_EXPLICIT}" = "0" ]; then + echo "BUILD: selected libc ${LIBC_IMPL} via EXPERIMENTAL_MUSL_DEFAULT=1" +else + echo "BUILD: selected libc ${LIBC_IMPL}" +fi + for stage in ${STAGES}; do if stage_is_current "${stage}"; then echo "BUILD: skipping ${stage} (up to date)" @@ -2356,6 +2823,7 @@ for stage in ${STAGES}; do # does not leave the working directory inside a source tree. BUILD_FUNC=build_${stage} ( "${BUILD_FUNC}" ) + refresh_build_fingerprints mark_stage_complete "${stage}" done diff --git a/configs/busybox-1.37.0.config b/configs/busybox-1.37.0.config index 8b39014..63a0af0 100644 --- a/configs/busybox-1.37.0.config +++ b/configs/busybox-1.37.0.config @@ -1140,8 +1140,8 @@ CONFIG_BASH_IS_NONE=y # CONFIG_CTTYHACK is not set CONFIG_HUSH=y CONFIG_SHELL_HUSH=y -CONFIG_HUSH_BASH_COMPAT=y -CONFIG_HUSH_BRACE_EXPANSION=y +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set # CONFIG_HUSH_BASH_SOURCE_CURDIR is not set CONFIG_HUSH_LINENO_VAR=y CONFIG_HUSH_INTERACTIVE=y diff --git a/configs/musl-smoke-workload.txt b/configs/musl-smoke-workload.txt new file mode 100644 index 0000000..a64cbc6 --- /dev/null +++ b/configs/musl-smoke-workload.txt @@ -0,0 +1,16 @@ +# label|command|expected regex +# +# Musl-specific runtime smoke layered on top of the generic BusyBox workload. +# Keep commands restricted to applets already enabled in configs/busybox-1.37.0.config. +loader-path|busybox ls -l /lib/ld-musl-arm-fdpic.so.1 >/dev/null && busybox echo ok|ok +libc-path|busybox ls /lib/libc.so >/dev/null && busybox echo ok|ok +shell-link|busybox ls -l /bin/sh >/dev/null && busybox echo ok|ok +uname|busybox uname -s >/dev/null && busybox echo ok|ok +list-bin|busybox ls /bin >/dev/null && busybox echo ok|ok +proc-version|busybox cat /proc/version >/dev/null && busybox echo ok|ok +proc-self-stat|busybox cat /proc/self/stat >/dev/null && busybox echo ok|ok +create-file|busybox sh -c 'busybox echo alpha >/tmp/musl-file && busybox cat /tmp/musl-file >/dev/null' && busybox echo ok|ok +copy-file|busybox sh -c 'busybox cp /bin/busybox /tmp/musl-copy && busybox ls /tmp/musl-copy >/dev/null' && busybox echo ok|ok +rename-file|busybox sh -c 'busybox mv /tmp/musl-file /tmp/musl-file-renamed && busybox cat /tmp/musl-file-renamed >/dev/null' && busybox echo ok|ok +hardlink-file|busybox sh -c 'busybox ln /tmp/musl-file-renamed /tmp/musl-file-link && busybox ls /tmp/musl-file-link >/dev/null' && busybox echo ok|ok +cleanup-tmp|busybox sh -c 'busybox rm -f /tmp/musl-file-renamed /tmp/musl-file-link /tmp/musl-copy' && busybox echo ok|ok diff --git a/patches/0024-musl-arm-fdpic-dynamic-linking.patch b/patches/0024-musl-arm-fdpic-dynamic-linking.patch new file mode 100644 index 0000000..33dd61c --- /dev/null +++ b/patches/0024-musl-arm-fdpic-dynamic-linking.patch @@ -0,0 +1,162 @@ +diff -uNr musl-patch-old/arch/arm/crt_arch.h musl-patch-new/arch/arm/crt_arch.h +--- musl-patch-old/arch/arm/crt_arch.h 2026-05-10 03:00:12.907245512 +0800 ++++ musl-patch-new/arch/arm/crt_arch.h 2026-05-10 03:00:12.907745845 +0800 +@@ -1,3 +1,61 @@ ++#ifdef __FDPIC__ ++ ++#if !defined(__thumb__) || defined(__thumb2__) ++__asm__( ++".text \n" ++".global " START " \n" ++".type " START ",%function \n" ++".thumb \n" ++".thumb_func \n" ++START ": \n" ++#ifdef SHARED ++" mov r4, sp \n" ++" sub r5, pc, #4 \n" ++" ldr r1, 1f \n" ++" add r1, r1, r5 \n" ++" ldr r2, 2f \n" ++" add r2, r2, r5 \n" ++" movs r0, r8 \n" ++" it eq \n" ++" moveq r0, r7 \n" ++" push {r7, r8, r9, r10} \n" ++" bl __fdpic_fixup \n" ++" pop {r7, r8, r9, r10} \n" ++" push {r7, r8} \n" ++" mov r1, r9 \n" ++" mov r9, r0 \n" ++" mov r0, r4 \n" ++" bl " START "_c \n" ++".align 2 \n" ++"1: .word __ROFIXUP_LIST__ - " START " \n" ++"2: .word __ROFIXUP_END__ - " START " \n" ++#else ++" sub r4, pc, #4 \n" ++" ldr r1, 1f \n" ++" add r1, r1, r4 \n" ++" ldr r2, 2f \n" ++" add r2, r2, r4 \n" ++" mov r0, r7 \n" ++" bl __self_reloc \n" ++" mov r9, r0 \n" ++" mov r0, sp \n" ++" movs r3, #0 \n" ++" mov fp, r3 \n" ++" bl " START "_c \n" ++".align 2 \n" ++"1: .word __ROFIXUP_LIST__ - " START " \n" ++"2: .word __ROFIXUP_END__ - " START " \n" ++#endif ++); ++ ++#include "fdpic_crt.h" ++ ++#else ++#error ARM FDPIC requires Thumb-2 or ARM mode support in crt startup ++#endif ++ ++#else ++ + __asm__( + ".text \n" + ".global " START " \n" +@@ -16,3 +74,5 @@ + ".align 2 \n" + "1: .word _DYNAMIC-2b \n" + ); ++ ++#endif +diff -uNr musl-patch-old/arch/arm/pthread_arch.h musl-patch-new/arch/arm/pthread_arch.h +--- musl-patch-old/arch/arm/pthread_arch.h 2026-05-10 03:00:12.907347137 +0800 ++++ musl-patch-new/arch/arm/pthread_arch.h 2026-05-10 03:00:12.907821595 +0800 +@@ -30,3 +30,8 @@ + #define GAP_ABOVE_TP 8 + + #define MC_PC arm_pc ++ ++#ifdef __FDPIC__ ++#define MC_GOT arm_r9 ++#define CANCEL_GOT (*(uintptr_t *)((char *)__syscall_cp_asm+sizeof(uintptr_t))) ++#endif +diff -uNr musl-patch-old/arch/arm/reloc.h musl-patch-new/arch/arm/reloc.h +--- musl-patch-old/arch/arm/reloc.h 2026-05-10 03:00:12.907433137 +0800 ++++ musl-patch-new/arch/arm/reloc.h 2026-05-10 03:00:12.907897512 +0800 +@@ -10,7 +10,13 @@ + #define FP_SUFFIX "" + #endif + +-#define LDSO_ARCH "arm" ENDIAN_SUFFIX FP_SUFFIX ++#if __FDPIC__ ++#define ABI_SUFFIX "-fdpic" ++#else ++#define ABI_SUFFIX "" ++#endif ++ ++#define LDSO_ARCH "arm" ENDIAN_SUFFIX FP_SUFFIX ABI_SUFFIX + + #define NO_LEGACY_INITFINI + +@@ -28,5 +34,41 @@ + + #define TLSDESC_BACKWARDS 1 + ++#if __FDPIC__ ++#ifndef R_ARM_FUNCDESC ++#define R_ARM_FUNCDESC 163 ++#endif ++#ifndef R_ARM_FUNCDESC_VALUE ++#define R_ARM_FUNCDESC_VALUE 164 ++#endif ++#define REL_FUNCDESC R_ARM_FUNCDESC ++#define REL_FUNCDESC_VAL R_ARM_FUNCDESC_VALUE ++#define DL_FDPIC 1 ++#define DL_NOMMU_SUPPORT 1 ++#define FDPIC_IS_RELATIVE(x,s) ( \ ++ (R_TYPE(x) == REL_RELATIVE) || \ ++ ((((R_TYPE(x) == REL_FUNCDESC_VAL) || \ ++ (R_TYPE(x) == REL_SYMBOLIC)) && \ ++ (((s)[R_SYM(x)].st_info & 0xf) == STT_SECTION))) ) ++#define CRTJMP(pc,sp) do { \ ++ register size_t r7 __asm__("r7") = ((size_t *)(sp))[-2]; \ ++ __asm__ __volatile__( \ ++ "mov sp,%1 ; bx %0" \ ++ : \ ++ : "r"(pc), "r"(sp), "r"(r7) \ ++ : "memory"); \ ++} while(0) ++#define GETFUNCSYM(fp, sym, got) __asm__ ( \ ++ "ldr %0, 1f \n" \ ++ "ldr %0, [%1, %0] \n" \ ++ "add %0, %0, %1 \n" \ ++ "b 2f \n" \ ++ ".align 2 \n" \ ++ "1: .word " #sym "(GOTFUNCDESC) \n" \ ++ "2: \n" \ ++ : "=&r"(*fp) : "r"(got) : "memory" ) ++#else ++ + #define CRTJMP(pc,sp) __asm__ __volatile__( \ + "mov sp,%1 ; bx %0" : : "r"(pc), "r"(sp) : "memory" ) ++#endif +diff -uNr musl-patch-old/src/internal/dynlink.h musl-patch-new/src/internal/dynlink.h +--- musl-patch-old/src/internal/dynlink.h 2026-05-10 03:00:12.907595304 +0800 ++++ musl-patch-new/src/internal/dynlink.h 2026-05-10 03:00:12.908054428 +0800 +@@ -82,11 +82,14 @@ + (R_TYPE(x) == REL_RELATIVE) || \ + (R_TYPE(x) == REL_SYM_OR_REL && !R_SYM(x)) ) + #else +-#define IS_RELATIVE(x,s) ( ( \ ++#ifndef FDPIC_IS_RELATIVE ++#define FDPIC_IS_RELATIVE(x,s) ( ( \ + (R_TYPE(x) == REL_FUNCDESC_VAL) || \ + (R_TYPE(x) == REL_SYMBOLIC) ) \ + && (((s)[R_SYM(x)].st_info & 0xf) == STT_SECTION) ) + #endif ++#define IS_RELATIVE(x,s) FDPIC_IS_RELATIVE(x,s) ++#endif + + #ifndef NEED_MIPS_GOT_RELOCS + #define NEED_MIPS_GOT_RELOCS 0 diff --git a/patches/0025-musl-tiny-iconv.patch b/patches/0025-musl-tiny-iconv.patch new file mode 100644 index 0000000..f8eae99 --- /dev/null +++ b/patches/0025-musl-tiny-iconv.patch @@ -0,0 +1,545 @@ +diff --git a/src/locale/iconv.c b/src/locale/iconv.c +index 175def1..b1d695f 100644 +--- a/src/locale/iconv.c ++++ b/src/locale/iconv.c +@@ -1,10 +1,9 @@ + #include + #include +-#include +-#include +-#include +-#include + #include ++#include ++#include ++#include + #include "locale_impl.h" + + #define UTF_32BE 0300 +@@ -19,21 +18,6 @@ + #define UTF_16 0312 + #define UTF_32 0313 + #define UCS2 0314 +-#define EUC_JP 0320 +-#define SHIFT_JIS 0321 +-#define ISO2022_JP 0322 +-#define GB18030 0330 +-#define GBK 0331 +-#define GB2312 0332 +-#define BIG5 0340 +-#define EUC_KR 0350 +- +-/* Definitions of charmaps. Each charmap consists of: +- * 1. Empty-string-terminated list of null-terminated aliases. +- * 2. Special type code or number of elided quads of entries. +- * 3. Character table (size determined by field 2), consisting +- * of 5 bytes for every 4 characters, interpreted as 10-bit +- * indices into the legacy_chars table. */ + + static const unsigned char charmaps[] = + "utf8\0char\0\0\310" +@@ -47,47 +31,11 @@ static const unsigned char charmaps[] = + "ascii\0usascii\0iso646\0iso646us\0\0\307" + "utf16\0\0\312" + "ucs4\0utf32\0\0\313" +-"ucs2\0\0\314" +-"eucjp\0\0\320" +-"shiftjis\0sjis\0cp932\0\0\321" +-"iso2022jp\0\0\322" +-"gb18030\0\0\330" +-"gbk\0\0\331" +-"gb2312\0\0\332" +-"big5\0bigfive\0cp950\0big5hkscs\0\0\340" +-"euckr\0ksc5601\0ksx1001\0cp949\0\0\350" +-#include "codepages.h" +-; +- +-/* Table of characters that appear in legacy 8-bit codepages, +- * limited to 1024 slots (10 bit indices). The first 256 entries +- * are elided since those characters are obviously all included. */ +-static const unsigned short legacy_chars[] = { +-#include "legacychars.h" +-}; ++"ucs2\0\0\314"; + +-static const unsigned short jis0208[84][94] = { +-#include "jis0208.h" +-}; +- +-static const unsigned short gb18030[126][190] = { +-#include "gb18030.h" +-}; +- +-static const unsigned short big5[89][157] = { +-#include "big5.h" +-}; +- +-static const unsigned short hkscs[] = { +-#include "hkscs.h" +-}; +- +-static const unsigned short ksc[93][94] = { +-#include "ksc.h" +-}; +- +-static const unsigned short rev_jis[] = { +-#include "revjis.h" ++struct stateful_cd { ++ iconv_t base_cd; ++ unsigned state; + }; + + static int fuzzycmp(const unsigned char *a, const unsigned char *b) +@@ -102,26 +50,18 @@ static int fuzzycmp(const unsigned char *a, const unsigned char *b) + static size_t find_charmap(const void *name) + { + const unsigned char *s; +- if (!*(char *)name) name=charmaps; /* "utf8" */ ++ if (!*(char *)name) name = charmaps; + for (s=charmaps; *s; ) { + if (!fuzzycmp(name, s)) { +- for (; *s; s+=strlen((void *)s)+1); +- return s+1-charmaps; +- } +- s += strlen((void *)s)+1; +- if (!*s) { +- if (s[1] > 0200) s+=2; +- else s+=2+(64U-s[1])*5; ++ for (; *s; s += strlen((void *)s) + 1); ++ return s + 1 - charmaps; + } ++ s += strlen((void *)s) + 1; ++ if (!*s) s += 2; + } + return -1; + } + +-struct stateful_cd { +- iconv_t base_cd; +- unsigned state; +-}; +- + static iconv_t combine_to_from(size_t t, size_t f) + { + return (void *)(f<<16 | t<<1 | 1); +@@ -142,19 +82,18 @@ iconv_t iconv_open(const char *to, const char *from) + size_t f, t; + struct stateful_cd *scd; + +- if ((t = find_charmap(to))==-1 +- || (f = find_charmap(from))==-1 +- || (charmaps[t] >= 0330)) { ++ if ((t = find_charmap(to)) == (size_t)-1 ++ || (f = find_charmap(from)) == (size_t)-1) { + errno = EINVAL; + return (iconv_t)-1; + } ++ + iconv_t cd = combine_to_from(t, f); + + switch (charmaps[f]) { + case UTF_16: + case UTF_32: + case UCS2: +- case ISO2022_JP: + scd = malloc(sizeof *scd); + if (!scd) return (iconv_t)-1; + scd->base_cd = cd; +@@ -193,49 +132,21 @@ static void put_32(unsigned char *s, unsigned c, int e) + s[e^3] = c; + } + +-/* Adapt as needed */ + #define mbrtowc_utf8 mbrtowc + #define wctomb_utf8 wctomb + +-static unsigned legacy_map(const unsigned char *map, unsigned c) +-{ +- if (c < 4*map[-1]) return c; +- unsigned x = c - 4*map[-1]; +- x = map[x*5/4]>>2*x%8 | map[x*5/4+1]<<8-2*x%8 & 1023; +- return x < 256 ? x : legacy_chars[x-256]; +-} +- +-static unsigned uni_to_jis(unsigned c) +-{ +- unsigned nel = sizeof rev_jis / sizeof *rev_jis; +- unsigned d, j, i, b = 0; +- for (;;) { +- i = nel/2; +- j = rev_jis[b+i]; +- d = jis0208[j/256][j%256]; +- if (d==c) return j + 0x2121; +- else if (nel == 1) return 0; +- else if (c < d) +- nel /= 2; +- else { +- b += i; +- nel -= nel/2; +- } +- } +-} +- + size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb) + { +- size_t x=0; +- struct stateful_cd *scd=0; ++ size_t x = 0; ++ struct stateful_cd *scd = 0; + if (!((size_t)cd & 1)) { + scd = (void *)cd; + cd = scd->base_cd; + } + unsigned to = extract_to(cd); + unsigned from = extract_from(cd); +- const unsigned char *map = charmaps+from+1; +- const unsigned char *tomap = charmaps+to+1; ++ const unsigned char *map = charmaps + from + 1; ++ const unsigned char *tomap = charmaps + to + 1; + mbstate_t st = {0}; + wchar_t wc; + unsigned c, d; +@@ -249,7 +160,7 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri + + *ploc = UTF8_LOCALE; + +- for (; *inb; *in+=l, *inb-=l) { ++ for (; *inb; *in += l, *inb -= l) { + c = *(unsigned char *)*in; + l = 1; + +@@ -303,8 +214,7 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri + scd->state = type==UCS2 + ? c==0xfffe ? UCS2LE : UCS2BE + : c==0xfffe ? UTF_16LE : UTF_16BE; +- if (c == 0xfffe || c == 0xfeff) +- l = 2; ++ if (c == 0xfffe || c == 0xfeff) l = 2; + } + type = scd->state; + continue; +@@ -314,214 +224,12 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri + if (*inb < 4) goto starved; + c = get_32((void *)*in, 0); + scd->state = c==0xfffe0000 ? UTF_32LE : UTF_32BE; +- if (c == 0xfffe0000 || c == 0xfeff) +- l = 4; ++ if (c == 0xfffe0000 || c == 0xfeff) l = 4; + } + type = scd->state; + continue; +- case SHIFT_JIS: +- if (c < 128) break; +- if (c-0xa1 <= 0xdf-0xa1) { +- c += 0xff61-0xa1; +- break; +- } +- l = 2; +- if (*inb < 2) goto starved; +- d = *((unsigned char *)*in + 1); +- if (c-129 <= 159-129) c -= 129; +- else if (c-224 <= 239-224) c -= 193; +- else goto ilseq; +- c *= 2; +- if (d-64 <= 158-64) { +- if (d==127) goto ilseq; +- if (d>127) d--; +- d -= 64; +- } else if (d-159 <= 252-159) { +- c++; +- d -= 159; +- } +- c = jis0208[c][d]; +- if (!c) goto ilseq; +- break; +- case EUC_JP: +- if (c < 128) break; +- l = 2; +- if (*inb < 2) goto starved; +- d = *((unsigned char *)*in + 1); +- if (c==0x8e) { +- c = d; +- if (c-0xa1 > 0xdf-0xa1) goto ilseq; +- c += 0xff61 - 0xa1; +- break; +- } +- c -= 0xa1; +- d -= 0xa1; +- if (c >= 84 || d >= 94) goto ilseq; +- c = jis0208[c][d]; +- if (!c) goto ilseq; +- break; +- case ISO2022_JP: +- if (c >= 128) goto ilseq; +- if (c == '\033') { +- l = 3; +- if (*inb < 3) goto starved; +- c = *((unsigned char *)*in + 1); +- d = *((unsigned char *)*in + 2); +- if (c != '(' && c != '$') goto ilseq; +- switch (128*(c=='$') + d) { +- case 'B': scd->state=0; continue; +- case 'J': scd->state=1; continue; +- case 'I': scd->state=4; continue; +- case 128+'@': scd->state=2; continue; +- case 128+'B': scd->state=3; continue; +- } +- goto ilseq; +- } +- switch (scd->state) { +- case 1: +- if (c=='\\') c = 0xa5; +- if (c=='~') c = 0x203e; +- break; +- case 2: +- case 3: +- l = 2; +- if (*inb < 2) goto starved; +- d = *((unsigned char *)*in + 1); +- c -= 0x21; +- d -= 0x21; +- if (c >= 84 || d >= 94) goto ilseq; +- c = jis0208[c][d]; +- if (!c) goto ilseq; +- break; +- case 4: +- if (c-0x60 < 0x1f) goto ilseq; +- if (c-0x21 < 0x5e) c += 0xff61-0x21; +- break; +- } +- break; +- case GB2312: +- if (c < 128) break; +- if (c < 0xa1) goto ilseq; +- case GBK: +- case GB18030: +- if (c < 128) break; +- c -= 0x81; +- if (c >= 126) goto ilseq; +- l = 2; +- if (*inb < 2) goto starved; +- d = *((unsigned char *)*in + 1); +- if (d < 0xa1 && type == GB2312) goto ilseq; +- if (d-0x40>=191 || d==127) { +- if (d-'0'>9 || type != GB18030) +- goto ilseq; +- l = 4; +- if (*inb < 4) goto starved; +- c = (10*c + d-'0') * 1260; +- d = *((unsigned char *)*in + 2); +- if (d-0x81>126) goto ilseq; +- c += 10*(d-0x81); +- d = *((unsigned char *)*in + 3); +- if (d-'0'>9) goto ilseq; +- c += d-'0'; +- c += 128; +- for (d=0; d<=c; ) { +- k = 0; +- for (int i=0; i<126; i++) +- for (int j=0; j<190; j++) +- if (gb18030[i][j]-d <= c-d) +- k++; +- d = c+1; +- c += k; +- } +- break; +- } +- d -= 0x40; +- if (d>63) d--; +- c = gb18030[c][d]; +- break; +- case BIG5: +- if (c < 128) break; +- l = 2; +- if (*inb < 2) goto starved; +- d = *((unsigned char *)*in + 1); +- if (d-0x40>=0xff-0x40 || d-0x7f<0xa1-0x7f) goto ilseq; +- d -= 0x40; +- if (d > 0x3e) d -= 0x22; +- if (c-0xa1>=0xfa-0xa1) { +- if (c-0x87>=0xff-0x87) goto ilseq; +- if (c < 0xa1) c -= 0x87; +- else c -= 0x87 + (0xfa-0xa1); +- c = (hkscs[4867+(c*157+d)/16]>>(c*157+d)%16)%2<<17 +- | hkscs[c*157+d]; +- /* A few HKSCS characters map to pairs of UCS +- * characters. These are mapped to surrogate +- * range in the hkscs table then hard-coded +- * here. Ugly, yes. */ +- if (c/256 == 0xdc) { +- union { +- char c[8]; +- wchar_t wc[2]; +- } tmp; +- char *ptmp = tmp.c; +- size_t tmpx = iconv(combine_to_from(to, find_charmap("utf8")), +- &(char *){"\303\212\314\204" +- "\303\212\314\214" +- "\303\252\314\204" +- "\303\252\314\214" +- +c%256}, &(size_t){4}, +- &ptmp, &(size_t){sizeof tmp}); +- size_t tmplen = ptmp - tmp.c; +- if (tmplen > *outb) goto toobig; +- if (tmpx) x++; +- memcpy(*out, &tmp, tmplen); +- *out += tmplen; +- *outb -= tmplen; +- continue; +- } +- if (!c) goto ilseq; +- break; +- } +- c -= 0xa1; +- c = big5[c][d]|(c==0x27&&(d==0x3a||d==0x3c||d==0x42))<<17; +- if (!c) goto ilseq; +- break; +- case EUC_KR: +- if (c < 128) break; +- l = 2; +- if (*inb < 2) goto starved; +- d = *((unsigned char *)*in + 1); +- c -= 0xa1; +- d -= 0xa1; +- if (c >= 93 || d >= 94) { +- c += (0xa1-0x81); +- d += 0xa1; +- if (c >= 93 || c>=0xc6-0x81 && d>0x52) +- goto ilseq; +- if (d-'A'<26) d = d-'A'; +- else if (d-'a'<26) d = d-'a'+26; +- else if (d-0x81<0xff-0x81) d = d-0x81+52; +- else goto ilseq; +- if (c < 0x20) c = 178*c + d; +- else c = 178*0x20 + 84*(c-0x20) + d; +- c += 0xac00; +- for (d=0xac00; d<=c; ) { +- k = 0; +- for (int i=0; i<93; i++) +- for (int j=0; j<94; j++) +- if (ksc[i][j]-d <= c-d) +- k++; +- d = c+1; +- c += k; +- } +- break; +- } +- c = ksc[c][d]; +- if (!c) goto ilseq; +- break; + default: +- if (!c) break; +- c = legacy_map(map, c); +- if (!c) goto ilseq; ++ goto ilseq; + } + + switch (totype) { +@@ -542,95 +250,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri + *outb -= k; + break; + case US_ASCII: +- if (c > 0x7f) subst: x++, c='*'; +- default: ++ if (c > 0x7f) x++, c = '*'; + if (*outb < 1) goto toobig; +- if (c<256 && c==legacy_map(tomap, c)) { +- revout: +- if (*outb < 1) goto toobig; +- *(*out)++ = c; +- *outb -= 1; +- break; +- } +- d = c; +- for (c=4*totype; c<256; c++) { +- if (d == legacy_map(tomap, c)) { +- goto revout; +- } +- } +- goto subst; +- case SHIFT_JIS: +- if (c < 128) goto revout; +- if (c == 0xa5) { +- x++; +- c = '\\'; +- goto revout; +- } +- if (c == 0x203e) { +- x++; +- c = '~'; +- goto revout; +- } +- if (c-0xff61 <= 0xdf-0xa1) { +- c += 0xa1 - 0xff61; +- goto revout; +- } +- c = uni_to_jis(c); +- if (!c) goto subst; +- if (*outb < 2) goto toobig; +- d = c%256; +- c = c/256; +- *(*out)++ = (c+1)/2 + (c<95 ? 112 : 176); +- *(*out)++ = c%2 ? d + 31 + d/96 : d + 126; +- *outb -= 2; +- break; +- case EUC_JP: +- if (c < 128) goto revout; +- if (c-0xff61 <= 0xdf-0xa1) { +- c += 0x0e00 + 0x21 - 0xff61; +- } else { +- c = uni_to_jis(c); +- } +- if (!c) goto subst; +- if (*outb < 2) goto toobig; +- *(*out)++ = c/256 + 0x80; +- *(*out)++ = c%256 + 0x80; +- *outb -= 2; +- break; +- case ISO2022_JP: +- if (c < 128) goto revout; +- if (c-0xff61 <= 0xdf-0xa1 || c==0xa5 || c==0x203e) { +- if (*outb < 7) goto toobig; +- *(*out)++ = '\033'; +- *(*out)++ = '('; +- if (c==0xa5) { +- *(*out)++ = 'J'; +- *(*out)++ = '\\'; +- } else if (c==0x203e) { +- *(*out)++ = 'J'; +- *(*out)++ = '~'; +- } else { +- *(*out)++ = 'I'; +- *(*out)++ = c-0xff61+0x21; +- } +- *(*out)++ = '\033'; +- *(*out)++ = '('; +- *(*out)++ = 'B'; +- *outb -= 7; +- break; +- } +- c = uni_to_jis(c); +- if (!c) goto subst; +- if (*outb < 8) goto toobig; +- *(*out)++ = '\033'; +- *(*out)++ = '$'; +- *(*out)++ = 'B'; +- *(*out)++ = c/256; +- *(*out)++ = c%256; +- *(*out)++ = '\033'; +- *(*out)++ = '('; +- *(*out)++ = 'B'; +- *outb -= 8; ++ *(*out)++ = c; ++ *outb -= 1; + break; + case UCS2: + totype = UCS2BE; +@@ -663,6 +286,8 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri + *out += 4; + *outb -= 4; + break; ++ default: ++ goto ilseq; + } + } + *ploc = loc; diff --git a/patches/0026-musl-allow-omitting-source-globs.patch b/patches/0026-musl-allow-omitting-source-globs.patch new file mode 100644 index 0000000..6d1b3af --- /dev/null +++ b/patches/0026-musl-allow-omitting-source-globs.patch @@ -0,0 +1,14 @@ +--- a/Makefile ++++ b/Makefile +@@ -6,8 +6,9 @@ + SRC_DIRS = $(addprefix $(srcdir)/,src/* src/malloc/$(MALLOC_DIR) crt ldso $(COMPAT_SRC_DIRS)) + BASE_GLOBS = $(addsuffix /*.c,$(SRC_DIRS)) + ARCH_GLOBS = $(addsuffix /$(ARCH)/*.[csS],$(SRC_DIRS)) +-BASE_SRCS = $(sort $(wildcard $(BASE_GLOBS))) +-ARCH_SRCS = $(sort $(wildcard $(ARCH_GLOBS))) ++OMIT_SRCS_GLOBS ?= ++BASE_SRCS = $(filter-out $(sort $(wildcard $(OMIT_SRCS_GLOBS))),$(sort $(wildcard $(BASE_GLOBS)))) ++ARCH_SRCS = $(filter-out $(sort $(wildcard $(OMIT_SRCS_GLOBS))),$(sort $(wildcard $(ARCH_GLOBS)))) + BASE_OBJS = $(patsubst $(srcdir)/%,%.o,$(basename $(BASE_SRCS))) + ARCH_OBJS = $(patsubst $(srcdir)/%,%.o,$(basename $(ARCH_SRCS))) + REPLACED_OBJS = $(sort $(subst /$(ARCH)/,/,$(ARCH_OBJS))) diff --git a/patches/0027-musl-busybox-only-c-locale-and-ascii-multibyte.patch b/patches/0027-musl-busybox-only-c-locale-and-ascii-multibyte.patch new file mode 100644 index 0000000..b5ce89d --- /dev/null +++ b/patches/0027-musl-busybox-only-c-locale-and-ascii-multibyte.patch @@ -0,0 +1,226 @@ +diff --git a/src/misc/busybox_ascii_wchar.c b/src/misc/busybox_ascii_wchar.c +new file mode 100644 +--- /dev/null ++++ b/src/misc/busybox_ascii_wchar.c +@@ -0,0 +1,221 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#undef iswdigit ++ ++static int ascii_isprint(wint_t wc) ++{ ++ return (unsigned)wc >= 0x20 && (unsigned)wc < 0x7f; ++} ++ ++int iswalnum(wint_t wc) { return (unsigned)wc < 256 && isalnum((unsigned char)wc); } ++int iswalpha(wint_t wc) { return (unsigned)wc < 256 && isalpha((unsigned char)wc); } ++int iswblank(wint_t wc) { return wc == ' ' || wc == '\t'; } ++int iswcntrl(wint_t wc) { return (unsigned)wc < 0x20 || wc == 0x7f; } ++int iswdigit(wint_t wc) { return (unsigned)(wc - '0') < 10; } ++int iswgraph(wint_t wc) { return ascii_isprint(wc) && !iswspace(wc); } ++int iswlower(wint_t wc) { return (unsigned)wc < 256 && islower((unsigned char)wc); } ++int iswprint(wint_t wc) { return ascii_isprint(wc) || ((unsigned)wc >= 0x80 && (unsigned)wc < 0x100); } ++int iswpunct(wint_t wc) { return (unsigned)wc < 256 && ispunct((unsigned char)wc); } ++int iswspace(wint_t wc) { return (unsigned)wc < 256 && isspace((unsigned char)wc); } ++int iswupper(wint_t wc) { return (unsigned)wc < 256 && isupper((unsigned char)wc); } ++int iswxdigit(wint_t wc) { return (unsigned)wc < 256 && isxdigit((unsigned char)wc); } ++ ++int iswctype(wint_t wc, wctype_t type) ++{ ++ switch (type) { ++ case 1: return iswalnum(wc); ++ case 2: return iswalpha(wc); ++ case 3: return iswblank(wc); ++ case 4: return iswcntrl(wc); ++ case 5: return iswdigit(wc); ++ case 6: return iswgraph(wc); ++ case 7: return iswlower(wc); ++ case 8: return iswprint(wc); ++ case 9: return iswpunct(wc); ++ case 10: return iswspace(wc); ++ case 11: return iswupper(wc); ++ case 12: return iswxdigit(wc); ++ } ++ return 0; ++} ++ ++wctype_t wctype(const char *s) ++{ ++ if (!strcmp(s, "alnum")) return 1; ++ if (!strcmp(s, "alpha")) return 2; ++ if (!strcmp(s, "blank")) return 3; ++ if (!strcmp(s, "cntrl")) return 4; ++ if (!strcmp(s, "digit")) return 5; ++ if (!strcmp(s, "graph")) return 6; ++ if (!strcmp(s, "lower")) return 7; ++ if (!strcmp(s, "print")) return 8; ++ if (!strcmp(s, "punct")) return 9; ++ if (!strcmp(s, "space")) return 10; ++ if (!strcmp(s, "upper")) return 11; ++ if (!strcmp(s, "xdigit")) return 12; ++ return 0; ++} ++ ++static const int wctrans_upper = 1; ++static const int wctrans_lower = 2; ++ ++wint_t towlower(wint_t wc) ++{ ++ if ((unsigned)wc < 256) return tolower((unsigned char)wc); ++ return wc; ++} ++ ++wint_t towupper(wint_t wc) ++{ ++ if ((unsigned)wc < 256) return toupper((unsigned char)wc); ++ return wc; ++} ++ ++wctrans_t wctrans(const char *class) ++{ ++ if (!strcmp(class, "toupper")) return &wctrans_upper; ++ if (!strcmp(class, "tolower")) return &wctrans_lower; ++ return 0; ++} ++ ++wint_t towctrans(wint_t wc, wctrans_t trans) ++{ ++ if (trans == &wctrans_upper) return towupper(wc); ++ if (trans == &wctrans_lower) return towlower(wc); ++ return wc; ++} ++ ++int wcwidth(wchar_t wc) ++{ ++ if (!wc) return 0; ++ return iswprint(wc) ? 1 : -1; ++} ++ ++int wcswidth(const wchar_t *wcs, size_t n) ++{ ++ int total = 0; ++ for (; n-- && *wcs; wcs++) { ++ int w = wcwidth(*wcs); ++ if (w < 0) return -1; ++ total += w; ++ } ++ return total; ++} ++ ++wint_t btowc(int c) ++{ ++ if (c == EOF) return WEOF; ++ return (unsigned char)c; ++} ++ ++int mbtowc(wchar_t *restrict wc, const char *restrict src, size_t n) ++{ ++ if (!src) return 0; ++ if (!n) { ++ errno = EILSEQ; ++ return -1; ++ } ++ if (wc) *wc = (unsigned char)*src; ++ return *src ? 1 : 0; ++} ++ ++int mblen(const char *s, size_t n) ++{ ++ return mbtowc(0, s, n); ++} ++ ++size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st) ++{ ++ (void)st; ++ if (!src) return 0; ++ if (!n) return (size_t)-2; ++ if (wc) *wc = (unsigned char)*src; ++ return *src ? 1 : 0; ++} ++ ++int mbsinit(const mbstate_t *st) ++{ ++ (void)st; ++ return 1; ++} ++ ++size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st) ++{ ++ (void)st; ++ if (!s) return 1; ++ if ((unsigned)wc > 0xff) { ++ errno = EILSEQ; ++ return (size_t)-1; ++ } ++ *s = (unsigned char)wc; ++ return 1; ++} ++ ++int wctomb(char *s, wchar_t wc) ++{ ++ size_t r; ++ if (!s) return 0; ++ r = wcrtomb(s, wc, 0); ++ return r == (size_t)-1 ? -1 : (int)r; ++} ++ ++size_t mbsnrtowcs(wchar_t *restrict dst, const char **restrict src, size_t nms, size_t len, mbstate_t *restrict st) ++{ ++ size_t i = 0; ++ (void)st; ++ if (!src || !*src) return 0; ++ if (!dst) { ++ while (i < nms && (*src)[i]) i++; ++ return i; ++ } ++ while (i < nms && i < len && (*src)[i]) { ++ dst[i] = (unsigned char)(*src)[i]; ++ i++; ++ } ++ if (i < nms && !(*src)[i]) *src = 0; ++ else *src += i; ++ return i; ++} ++ ++size_t mbsrtowcs(wchar_t *restrict dst, const char **restrict src, size_t len, mbstate_t *restrict st) ++{ ++ size_t n = *src ? strlen(*src) + 1 : 0; ++ size_t r = mbsnrtowcs(dst, src, n, len, st); ++ if (dst && r < len && !*src) return r; ++ return r; ++} ++ ++size_t mbstowcs(wchar_t *restrict dst, const char *restrict src, size_t len) ++{ ++ const char *p = src; ++ return mbsrtowcs(dst, &p, len, 0); ++} ++ ++size_t wcsrtombs(char *restrict dst, const wchar_t **restrict src, size_t len, mbstate_t *restrict st) ++{ ++ size_t i = 0; ++ (void)st; ++ if (!src || !*src) return 0; ++ if (!dst) { ++ while ((*src)[i]) i++; ++ return i; ++ } ++ while (i < len && (*src)[i]) { ++ if ((unsigned)(*src)[i] > 0xff) { ++ errno = EILSEQ; ++ return (size_t)-1; ++ } ++ dst[i] = (unsigned char)(*src)[i]; ++ i++; ++ } ++ if (i < len && !(*src)[i]) *src = 0; ++ else *src += i; ++ return i; ++} ++ diff --git a/patches/0028-musl-busybox-only-c-locale.patch b/patches/0028-musl-busybox-only-c-locale.patch new file mode 100644 index 0000000..5106fb0 --- /dev/null +++ b/patches/0028-musl-busybox-only-c-locale.patch @@ -0,0 +1,136 @@ +diff --git a/src/misc/busybox_c_locale.c b/src/misc/busybox_c_locale.c +new file mode 100644 +--- /dev/null ++++ b/src/misc/busybox_c_locale.c +@@ -0,0 +1,131 @@ ++#include ++#include ++#include ++#include ++#include ++#include "locale_impl.h" ++ ++static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 }; ++ ++const struct __locale_map __c_dot_utf8 = { ++ .map = empty_mo, ++ .map_size = sizeof empty_mo, ++ .name = "C.UTF-8" ++}; ++ ++const struct __locale_struct __c_locale = { 0 }; ++const struct __locale_struct __c_dot_utf8_locale = { ++ .cat[LC_CTYPE] = &__c_dot_utf8 ++}; ++ ++static const char c_time[] = ++ "Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0" ++ "Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0" ++ "Thursday\0" "Friday\0" "Saturday\0" ++ "Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0" ++ "Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0" ++ "January\0" "February\0" "March\0" "April\0" ++ "May\0" "June\0" "July\0" "August\0" ++ "September\0" "October\0" "November\0" "December\0" ++ "AM\0" "PM\0" ++ "%a %b %e %T %Y\0" ++ "%m/%d/%y\0" ++ "%H:%M:%S\0" ++ "%I:%M:%S %p\0" ++ "\0" ++ "\0" ++ "%m/%d/%y\0" ++ "0123456789\0" ++ "%a %b %e %T %Y\0" ++ "%H:%M:%S"; ++ ++static const char c_messages[] = "^[yY]\0" "^[nN]\0" "yes\0" "no"; ++static const char c_numeric[] = ".\0" ""; ++ ++static struct lconv c_lconv = { ++ .decimal_point = ".", ++ .thousands_sep = "", ++ .grouping = "", ++ .int_curr_symbol = "", ++ .currency_symbol = "", ++ .mon_decimal_point = "", ++ .mon_thousands_sep = "", ++ .mon_grouping = "", ++ .positive_sign = "", ++ .negative_sign = "", ++ .int_frac_digits = CHAR_MAX, ++ .frac_digits = CHAR_MAX, ++ .p_cs_precedes = CHAR_MAX, ++ .p_sep_by_space = CHAR_MAX, ++ .n_cs_precedes = CHAR_MAX, ++ .n_sep_by_space = CHAR_MAX, ++ .p_sign_posn = CHAR_MAX, ++ .n_sign_posn = CHAR_MAX, ++ .int_p_cs_precedes = CHAR_MAX, ++ .int_p_sep_by_space = CHAR_MAX, ++ .int_n_cs_precedes = CHAR_MAX, ++ .int_n_sep_by_space = CHAR_MAX, ++ .int_p_sign_posn = CHAR_MAX, ++ .int_n_sign_posn = CHAR_MAX, ++}; ++ ++char *setlocale(int cat, const char *name) ++{ ++ if ((unsigned)cat > LC_ALL) return 0; ++ if (!name || !*name) return "C"; ++ if (!strcmp(name, "C") || !strcmp(name, "POSIX") || !strcmp(name, "C.UTF-8")) ++ return "C"; ++ return 0; ++} ++ ++struct lconv *localeconv(void) ++{ ++ return &c_lconv; ++} ++ ++char *__nl_langinfo_l(nl_item item, locale_t loc) ++{ ++ int cat = item >> 16; ++ int idx = item & 65535; ++ const char *str; ++ (void)loc; ++ ++ if (item == CODESET) return "ASCII"; ++ if (idx == 65535 && cat < LC_ALL) return "C"; ++ ++ switch (cat) { ++ case LC_NUMERIC: ++ if (idx > 1) return ""; ++ str = c_numeric; ++ break; ++ case LC_TIME: ++ if (idx > 0x31) return ""; ++ str = c_time; ++ break; ++ case LC_MESSAGES: ++ if (idx > 3) return ""; ++ str = c_messages; ++ break; ++ default: ++ return ""; ++ } ++ ++ for (; idx; idx--, str++) for (; *str; str++) {} ++ return (char *)str; ++} ++ ++char *nl_langinfo(nl_item item) ++{ ++ return __nl_langinfo_l(item, 0); ++} ++ ++hidden const char *__lctrans(const char *msg, const struct __locale_map *lm) ++{ ++ (void)lm; ++ return msg; ++} ++ ++hidden const char *__lctrans_cur(const char *msg) { return msg; } ++int strcoll(const char *l, const char *r) { return strcmp(l, r); } ++int strcoll_l(const char *l, const char *r, locale_t loc) { (void)loc; return strcmp(l, r); } ++ diff --git a/patches/0029-musl-busybox-only-disable-runtime-dlfcn.patch b/patches/0029-musl-busybox-only-disable-runtime-dlfcn.patch new file mode 100644 index 0000000..130016a --- /dev/null +++ b/patches/0029-musl-busybox-only-disable-runtime-dlfcn.patch @@ -0,0 +1,19 @@ +diff --git a/ldso/dynlink.c b/ldso/dynlink.c +--- a/ldso/dynlink.c ++++ b/ldso/dynlink.c +@@ -2098,6 +2098,7 @@ static void prepare_lazy(struct dso *p) + } + } + ++#ifndef MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL + void *dlopen(const char *file, int mode) + { + struct dso *volatile p, *orig_tail, *orig_syms_tail, *orig_lazy_head, *next; +@@ -2415,6 +2416,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void + } + return ret; + } ++#endif + + static void error_impl(const char *fmt, ...) + { diff --git a/patches/0030-musl-busybox-only-minimal-dlfcn-stubs.patch b/patches/0030-musl-busybox-only-minimal-dlfcn-stubs.patch new file mode 100644 index 0000000..fd1b452 --- /dev/null +++ b/patches/0030-musl-busybox-only-minimal-dlfcn-stubs.patch @@ -0,0 +1,130 @@ +diff -ruN orig/src/ldso/__dlsym.c new/src/ldso/__dlsym.c +--- a/src/ldso/__dlsym.c 2026-05-10 00:25:35.797548649 +0800 ++++ b/src/ldso/__dlsym.c 2026-05-10 00:25:35.802624237 +0800 +@@ -1,11 +1,21 @@ + #include + #include "dynlink.h" + ++#ifdef MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL ++static void *stub_dlsym(void *restrict p, const char *restrict s, void *restrict ra) ++{ ++ (void)p; ++ (void)s; ++ (void)ra; ++ return 0; ++} ++#else + static void *stub_dlsym(void *restrict p, const char *restrict s, void *restrict ra) + { + __dl_seterr("Symbol not found: %s", s); + return 0; + } ++#endif + + weak_alias(stub_dlsym, __dlsym); + +diff -ruN orig/src/ldso/dlclose.c new/src/ldso/dlclose.c +--- a/src/ldso/dlclose.c 2026-05-10 00:25:35.806932517 +0800 ++++ b/src/ldso/dlclose.c 2026-05-10 00:25:35.810635524 +0800 +@@ -1,7 +1,15 @@ + #include + #include "dynlink.h" + ++#ifdef MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL ++int dlclose(void *p) ++{ ++ (void)p; ++ return -1; ++} ++#else + int dlclose(void *p) + { + return __dl_invalid_handle(p); + } ++#endif +diff -ruN orig/src/ldso/dlerror.c new/src/ldso/dlerror.c +--- a/src/ldso/dlerror.c 2026-05-10 00:25:35.814381447 +0800 ++++ b/src/ldso/dlerror.c 2026-05-10 00:25:35.817564637 +0800 +@@ -1,3 +1,4 @@ ++#ifndef MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL + #include + #include + #include +@@ -87,3 +88,30 @@ + } + + weak_alias(stub_invalid_handle, __dl_invalid_handle); ++#else ++#include ++#include ++#include "dynlink.h" ++ ++char *dlerror() ++{ ++ return 0; ++} ++ ++hidden void __dl_vseterr(const char *fmt, va_list ap) ++{ ++ (void)fmt; ++ (void)ap; ++} ++ ++hidden void __dl_seterr(const char *fmt, ...) ++{ ++ (void)fmt; ++} ++ ++hidden int __dl_invalid_handle(void *h) ++{ ++ (void)h; ++ return 1; ++} ++#endif +diff -ruN orig/src/ldso/dlinfo.c new/src/ldso/dlinfo.c +--- a/src/ldso/dlinfo.c 2026-05-10 00:25:35.821284394 +0800 ++++ b/src/ldso/dlinfo.c 2026-05-10 00:25:35.824962652 +0800 +@@ -1,3 +1,4 @@ ++#ifndef MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL + #define _GNU_SOURCE + #include + #include "dynlink.h" +@@ -12,3 +13,15 @@ + *(struct link_map **)res = dso; + return 0; + } ++#else ++#define _GNU_SOURCE ++#include ++ ++int dlinfo(void *dso, int req, void *res) ++{ ++ (void)dso; ++ (void)req; ++ (void)res; ++ return -1; ++} ++#endif +diff -ruN orig/src/ldso/dlopen.c new/src/ldso/dlopen.c +--- a/src/ldso/dlopen.c 2026-05-10 00:25:35.828244756 +0800 ++++ b/src/ldso/dlopen.c 2026-05-10 00:25:35.831609857 +0800 +@@ -1,10 +1,19 @@ + #include + #include "dynlink.h" + ++#ifdef MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL ++static void *stub_dlopen(const char *file, int mode) ++{ ++ (void)file; ++ (void)mode; ++ return 0; ++} ++#else + static void *stub_dlopen(const char *file, int mode) + { + __dl_seterr("Dynamic loading not supported"); + return 0; + } ++#endif + + weak_alias(stub_dlopen, dlopen); diff --git a/patches/0031-musl-busybox-only-no-tzfile.patch b/patches/0031-musl-busybox-only-no-tzfile.patch new file mode 100644 index 0000000..0b35f97 --- /dev/null +++ b/patches/0031-musl-busybox-only-no-tzfile.patch @@ -0,0 +1,95 @@ +--- a/src/time/__tz.c 2026-05-10 00:36:50.701456468 +0800 ++++ b/src/time/__tz.c 2026-05-10 00:38:48.865708297 +0800 +@@ -2,8 +2,10 @@ + #include + #include + #include +-#include ++#ifndef MUSL_BUSYBOX_ONLY_NO_TZFILE + #include ++#endif ++#include + #include + #include "libc.h" + #include "lock.h" +@@ -125,22 +127,30 @@ + + static void do_tzset() + { ++#ifndef MUSL_BUSYBOX_ONLY_NO_TZFILE + char buf[NAME_MAX+25], *pathname=buf+24; + const char *try, *s, *p; + const unsigned char *map = 0; +- size_t i; + static const char search[] = + "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0"; ++#else ++ const char *s, *p; ++#endif ++ size_t i; + + s = getenv("TZ"); ++#ifndef MUSL_BUSYBOX_ONLY_NO_TZFILE + if (!s) s = "/etc/localtime"; ++#endif + if (!*s) s = __utc; + + if (old_tz && !strcmp(s, old_tz)) return; + + for (i=0; i<5; i++) r0[i] = r1[i] = 0; + ++#ifndef MUSL_BUSYBOX_ONLY_NO_TZFILE + if (zi) __munmap((void *)zi, map_size); ++#endif + + /* Cache the old value of TZ to check if it has changed. Avoid + * free so as not to pull it into static programs. Growth +@@ -164,12 +174,13 @@ + || !strcmp(dummy_name, "UTC") + || !strcmp(dummy_name, "GMT"))) + posix_form = 1; +- } ++ } + +- /* Non-suid can use an absolute tzfile pathname or a relative +- * pathame beginning with "."; in secure mode, only the +- * standard path will be searched. */ + if (!posix_form) { ++#ifndef MUSL_BUSYBOX_ONLY_NO_TZFILE ++ /* Non-suid can use an absolute tzfile pathname or a relative ++ * pathname beginning with "."; in secure mode, only the ++ * standard path will be searched. */ + if (*s == ':') s++; + if (*s == '/' || *s == '.') { + if (!libc.secure || !strcmp(s, "/etc/localtime")) +@@ -187,7 +198,12 @@ + } + } + if (!map) s = __utc; ++#else ++ s = __utc; ++#endif + } ++ ++#ifndef MUSL_BUSYBOX_ONLY_NO_TZFILE + if (map && (map_size < 44 || memcmp(map, "TZif", 4))) { + __munmap((void *)map, map_size); + map = 0; +@@ -235,6 +251,9 @@ + return; + } + } ++#else ++ zi = 0; ++#endif + + if (!s) s = __utc; + getname(std_name, &s); +@@ -256,7 +275,6 @@ + if (*s == ',') s++, getrule(&s, r0); + if (*s == ',') s++, getrule(&s, r1); + } +- + /* Search zoneinfo rules to find the one that applies to the given time, + * and determine alternate opposite-DST-status rule that may be needed. */ + diff --git a/patches/0032-busybox-only-disable-float-printf.patch b/patches/0032-busybox-only-disable-float-printf.patch new file mode 100644 index 0000000..7c9e75c --- /dev/null +++ b/patches/0032-busybox-only-disable-float-printf.patch @@ -0,0 +1,48 @@ +--- a/coreutils/printf.c ++++ b/coreutils/printf.c +@@ -117,6 +117,7 @@ + arg++; + *(long long*)result = bb_strtoll(arg, NULL, 0); + } ++#ifndef BUSYBOX_ONLY_NO_PRINTF_FLOAT + static void FAST_FUNC conv_strtod(const char *arg, void *result) + { + char *end; +@@ -130,6 +131,7 @@ + *(double*)result = 0; + } + } ++#endif + + /* Callers should check errno to detect errors */ + static unsigned long long my_xstrtoull(const char *arg) +@@ -147,6 +149,7 @@ + result = 0; + return result; + } ++#ifndef BUSYBOX_ONLY_NO_PRINTF_FLOAT + static double my_xstrtod(const char *arg) + { + double result; +@@ -154,6 +157,7 @@ + multiconvert(arg, &result, conv_strtod); + return result; + } ++#endif + + /* Handles %b; return 1 if output is to be short-circuited by \c */ + static int print_esc_string(const char *str) +@@ -256,7 +260,13 @@ + case 'E': + case 'g': + case 'G': ++#ifdef BUSYBOX_ONLY_NO_PRINTF_FLOAT ++ errno = ERANGE; ++ dv = 0; ++ bb_error_msg("floating point formats are disabled"); ++#else + dv = my_xstrtod(argument); ++#endif + if (!have_width) { + if (!have_prec) + printf(format, dv); diff --git a/patches/0033-musl-fdpic-dlstart-direct-dls2.patch b/patches/0033-musl-fdpic-dlstart-direct-dls2.patch new file mode 100644 index 0000000..1054ab1 --- /dev/null +++ b/patches/0033-musl-fdpic-dlstart-direct-dls2.patch @@ -0,0 +1,26 @@ +diff -uNr musl-patch-old/ldso/dlstart.c musl-patch-new/ldso/dlstart.c +--- musl-patch-old/ldso/dlstart.c 2026-05-10 03:00:12.907595304 +0800 ++++ musl-patch-new/ldso/dlstart.c 2026-05-10 03:00:12.908054428 +0800 +@@ -15,6 +15,10 @@ + __asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \ + *(fp) = static_func_ptr; } while(0) + #endif ++ ++#if DL_FDPIC ++hidden void __dls2(unsigned char *, size_t *); ++#endif + + hidden void _dlstart_c(size_t *sp, size_t *dynv) + { +@@ -154,7 +158,11 @@ + } + #endif + ++#if DL_FDPIC ++ __dls2((void *)base, sp); ++#else + stage2_func dls2; + GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]); + dls2((void *)base, sp); ++#endif + } diff --git a/patches/0034-musl-arm-fdpic-soft-tp.patch b/patches/0034-musl-arm-fdpic-soft-tp.patch new file mode 100644 index 0000000..fd57b67 --- /dev/null +++ b/patches/0034-musl-arm-fdpic-soft-tp.patch @@ -0,0 +1,98 @@ +diff -uNr musl-patch-old/arch/arm/pthread_arch.h musl-patch-new/arch/arm/pthread_arch.h +--- musl-patch-old/arch/arm/pthread_arch.h 2026-05-10 03:00:12.907347137 +0800 ++++ musl-patch-new/arch/arm/pthread_arch.h 2026-05-10 03:00:12.907821595 +0800 +@@ -1,5 +1,5 @@ +-#if ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ +- || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 ++#if !defined(__FDPIC__) && (((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ ++ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7) + + static inline uintptr_t __get_tp() + { +diff -uNr musl-patch-old/src/ldso/arm/tlsdesc.S musl-patch-new/src/ldso/arm/tlsdesc.S +--- musl-patch-old/src/ldso/arm/tlsdesc.S 2026-05-10 03:00:12.907595304 +0800 ++++ musl-patch-new/src/ldso/arm/tlsdesc.S 2026-05-10 03:00:12.908054428 +0800 +@@ -13,7 +13,7 @@ + ldr r2,[r1,#4] // r2 = offset + ldr r1,[r1] // r1 = modid + +-#if ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ +- || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 ++#if !defined(__FDPIC__) && (((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ ++ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7) + mrc p15,0,r0,c13,c0,3 + #else +@@ -39,8 +39,8 @@ + pop {r2,r3,ip,lr} + bx lr + #endif + +-#if ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ +- || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 ++#if !defined(__FDPIC__) && (((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ ++ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7) + #else + .align 2 +diff -uNr musl-patch-old/src/thread/arm/__set_thread_area.c musl-patch-new/src/thread/arm/__set_thread_area.c +--- musl-patch-old/src/thread/arm/__set_thread_area.c 2026-05-10 03:00:12.907595304 +0800 ++++ musl-patch-new/src/thread/arm/__set_thread_area.c 2026-05-10 03:00:12.908054428 +0800 +@@ -7,7 +7,7 @@ + extern hidden const unsigned char + __a_barrier_oldkuser[], __a_barrier_v6[], __a_barrier_v7[], + __a_cas_v6[], __a_cas_v7[], +- __a_gettp_cp15[]; ++ __a_gettp_cp15[], __a_gettp_soft[]; + + #define __a_barrier_kuser 0xffff0fa0 + #define __a_barrier_oldkuser (uintptr_t)__a_barrier_oldkuser +@@ -18,10 +18,18 @@ + #define __a_cas_v7 (uintptr_t)__a_cas_v7 + + #define __a_gettp_kuser 0xffff0fe0 ++#define __a_gettp_soft (uintptr_t)__a_gettp_soft + #define __a_gettp_cp15 (uintptr_t)__a_gettp_cp15 + + extern hidden uintptr_t __a_barrier_ptr, __a_cas_ptr, __a_gettp_ptr; + + int __set_thread_area(void *p) + { ++#if __FDPIC__ ++ __a_barrier_ptr = __a_barrier_v7; ++ __a_cas_ptr = __a_cas_v7; ++ __a_gettp_ptr = __a_gettp_soft; ++ return __syscall(0xf0005, p); ++#endif ++ + #if !__ARM_ARCH_7A__ && !__ARM_ARCH_7R__ && __ARM_ARCH < 7 + if (__hwcap & HWCAP_TLS) { + size_t *aux; +diff -uNr musl-patch-old/src/thread/arm/atomics.s musl-patch-new/src/thread/arm/atomics.s +--- musl-patch-old/src/thread/arm/atomics.s 2026-05-10 03:00:12.907595304 +0800 ++++ musl-patch-new/src/thread/arm/atomics.s 2026-05-10 03:00:12.908054428 +0800 +@@ -81,6 +81,17 @@ + mrc p15,0,r0,c13,c0,3 + bx lr + ++.global __a_gettp_soft ++.hidden __a_gettp_soft ++.type __a_gettp_soft,%function ++__a_gettp_soft: ++ push {r7} ++ mov r7, #0x0f0000 ++ orr r7, r7, #6 ++ svc #0 ++ pop {r7} ++ bx lr ++ + /* Tag this file with minimum ISA level so as not to affect linking. */ + .object_arch armv4t + .eabi_attribute 6,2 +@@ -103,4 +116,8 @@ + .global __a_gettp_ptr + .hidden __a_gettp_ptr + __a_gettp_ptr: ++#if __FDPIC__ ++ .word __a_gettp_soft ++#else + .word __a_gettp_cp15 ++#endif diff --git a/patches/0035-musl-fdpic-local-funcdesc-got.patch b/patches/0035-musl-fdpic-local-funcdesc-got.patch new file mode 100644 index 0000000..ec18fe3 --- /dev/null +++ b/patches/0035-musl-fdpic-local-funcdesc-got.patch @@ -0,0 +1,15 @@ +diff -uNr musl-patch-old/ldso/dynlink.c musl-patch-new/ldso/dynlink.c +--- musl-patch-old/ldso/dynlink.c 2026-05-10 03:00:12.907595304 +0800 ++++ musl-patch-new/ldso/dynlink.c 2026-05-10 03:00:12.908054428 +0800 +@@ -515,7 +515,10 @@ + case REL_FUNCDESC_VAL: + if ((sym->st_info&0xf) == STT_SECTION) *reloc_addr += sym_val; + else *reloc_addr = sym_val; +- reloc_addr[1] = def.sym ? (size_t)def.dso->got : 0; ++ if ((sym->st_info&0xf) == STT_SECTION) ++ reloc_addr[1] = (size_t)dso->got; ++ else ++ reloc_addr[1] = def.sym ? (size_t)def.dso->got : 0; + break; + case REL_DTPMOD: + *reloc_addr = def.dso->tls_id; diff --git a/patches/0036-musl-fdpic-dlstart-handle-rel.patch b/patches/0036-musl-fdpic-dlstart-handle-rel.patch new file mode 100644 index 0000000..bcb679c --- /dev/null +++ b/patches/0036-musl-fdpic-dlstart-handle-rel.patch @@ -0,0 +1,89 @@ +diff -uNr musl-patch-old/ldso/dlstart.c musl-patch-new/ldso/dlstart.c +--- musl-patch-old/ldso/dlstart.c ++++ musl-patch-new/ldso/dlstart.c +@@ -35,11 +35,12 @@ + + #if DL_FDPIC + struct fdpic_loadseg *segs, fakeseg; +- size_t j; ++ size_t j, nsegs; + if (dynv) { + /* crt_arch.h entry point asm is responsible for reserving + * space and moving the extra fdpic arguments to the stack + * vector where they are easily accessible from C. */ + segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs; ++ nsegs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->nsegs; + } else { + /* If dynv is null, the entry point was started from loader +@@ -50,6 +51,7 @@ + base = aux[AT_BASE]; + if (!base) base = aux[AT_PHDR] & -4096; + segs = &fakeseg; ++ nsegs = 1; + segs[0].addr = base; + segs[0].p_vaddr = 0; + segs[0].p_memsz = -1; +@@ -78,6 +80,35 @@ + + const Sym *syms = (void *)dyn[DT_SYMTAB]; + ++ rel = (void *)dyn[DT_REL]; ++ rel_size = dyn[DT_RELSZ]; ++ for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) { ++ if (!IS_RELATIVE(rel[1], syms)) continue; ++ for (j=0; j= segs[j].p_memsz; j++); ++ if (j == nsegs) __builtin_trap(); ++ size_t *rel_addr = (void *) ++ (rel[0] + segs[j].addr - segs[j].p_vaddr); ++ size_t sym_val = syms[R_SYM(rel[1])].st_value; ++ if (R_SYM(rel[1])) { ++ for (j=0; j= segs[j].p_memsz; j++); ++ if (j == nsegs) __builtin_trap(); ++ sym_val += segs[j].addr - segs[j].p_vaddr; ++ } ++ if (R_TYPE(rel[1]) == REL_RELATIVE) { ++ size_t val = *rel_addr; ++ for (j=0; j= segs[j].p_memsz; j++); ++ if (j == nsegs) __builtin_trap(); ++ *rel_addr = val + segs[j].addr - segs[j].p_vaddr; ++ } else if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) { ++ if ((syms[R_SYM(rel[1])].st_info & 0xf) == STT_SECTION) ++ *rel_addr += sym_val; ++ else ++ *rel_addr = sym_val; ++ rel_addr[1] = dyn[DT_PLTGOT]; ++ } else { ++ *rel_addr += sym_val; ++ } ++ } + rel = (void *)dyn[DT_RELA]; + rel_size = dyn[DT_RELASZ]; + for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) { +@@ -85,14 +116,21 @@ + for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++); + size_t *rel_addr = (void *) + (rel[0] + segs[j].addr - segs[j].p_vaddr); ++ size_t sym_val = syms[R_SYM(rel[1])].st_value; ++ if (R_SYM(rel[1])) { ++ for (j=0; j= segs[j].p_memsz; j++); ++ if (j == nsegs) __builtin_trap(); ++ sym_val += segs[j].addr - segs[j].p_vaddr; ++ } + if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) { +- *rel_addr += segs[rel_addr[1]].addr +- - segs[rel_addr[1]].p_vaddr +- + syms[R_SYM(rel[1])].st_value; ++ *rel_addr += sym_val; + rel_addr[1] = dyn[DT_PLTGOT]; ++ } else if (R_TYPE(rel[1]) == REL_RELATIVE) { ++ size_t val = rel[2]; ++ for (j=0; j= segs[j].p_memsz; j++); ++ if (j == nsegs) __builtin_trap(); ++ *rel_addr = val + segs[j].addr - segs[j].p_vaddr; + } else { +- size_t val = syms[R_SYM(rel[1])].st_value; +- for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++); +- *rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val; ++ *rel_addr = rel[2] + sym_val; + } + } diff --git a/patches/0037-musl-fdpic-init-array-fpaddr.patch b/patches/0037-musl-fdpic-init-array-fpaddr.patch new file mode 100644 index 0000000..725ef0f --- /dev/null +++ b/patches/0037-musl-fdpic-init-array-fpaddr.patch @@ -0,0 +1,37 @@ +diff -uNr musl-patch-old/ldso/dynlink.c musl-patch-new/ldso/dynlink.c +--- musl-patch-old/ldso/dynlink.c ++++ musl-patch-new/ldso/dynlink.c +@@ -1507,8 +1507,14 @@ + decode_vec(p->dynv, dyn, DYN_CNT); + if (dyn[0] & (1<st_size); diff --git a/patches/0039-musl-arm-fdpic-xip-aware-loadmap-and-textrel.patch b/patches/0039-musl-arm-fdpic-xip-aware-loadmap-and-textrel.patch new file mode 100644 index 0000000..883d59e --- /dev/null +++ b/patches/0039-musl-arm-fdpic-xip-aware-loadmap-and-textrel.patch @@ -0,0 +1,128 @@ +diff -uNr musl-patch-old/src/internal/dynlink.h musl-patch-new/src/internal/dynlink.h +--- musl-patch-old/src/internal/dynlink.h ++++ musl-patch-new/src/internal/dynlink.h +@@ -94,7 +94,7 @@ + #define DT_DEBUG_INDIRECT_REL 0 + #endif + +-#define AUX_CNT 32 ++#define AUX_CNT 45 + #define DYN_CNT 37 + + typedef void (*stage2_func)(unsigned char *, size_t *); +diff -uNr musl-patch-old/arch/arm/reloc.h musl-patch-new/arch/arm/reloc.h +--- musl-patch-old/arch/arm/reloc.h ++++ musl-patch-new/arch/arm/reloc.h +@@ -43,4 +43,12 @@ + #define REL_FUNCDESC R_ARM_FUNCDESC + #define REL_FUNCDESC_VAL R_ARM_FUNCDESC_VALUE + #define DL_FDPIC 1 ++#ifndef DL_FDPIC_STRICT_XIP ++/* This Cortex-M FDPIC target is always XIP-oriented, so keep strict ++ * DT_TEXTREL rejection enabled by default. Must remain a preprocessor ++ * constant so FDPIC/XIP policy can be consumed from both runtime code ++ * and preprocessor gates. */ ++#define DL_FDPIC_STRICT_XIP 1 ++#endif ++ + #define DL_NOMMU_SUPPORT 1 +diff -uNr musl-patch-old/ldso/dynlink.c musl-patch-new/ldso/dynlink.c +--- musl-patch-old/ldso/dynlink.c ++++ musl-patch-new/ldso/dynlink.c +@@ -197,26 +197,45 @@ + + /* Compute load address for a virtual address in a given dso. */ + #if DL_FDPIC ++static int fdpic_loadseg_contains_vaddr(const struct fdpic_loadseg *seg, ++ size_t v, int last) ++{ ++ size_t off; ++ ++ if (v < seg->p_vaddr) return 0; ++ off = v - seg->p_vaddr; ++ return off < seg->p_memsz || (last && off == seg->p_memsz); ++} ++ ++static int fdpic_loadseg_contains_page(const struct fdpic_loadseg *seg, ++ size_t v, size_t pgsz) ++{ ++ size_t a = seg->p_vaddr & -pgsz; ++ size_t bias = seg->p_vaddr - a; ++ size_t span = seg->p_memsz; ++ ++ if (v < a) return 0; ++ if (span > (size_t)-1 - bias) span = (size_t)-1; ++ else span += bias; ++ if (span > (size_t)-1 - (pgsz-1)) span = (size_t)-1; ++ else span = (span + pgsz-1) & -pgsz; ++ return v-a < span; ++} ++ + static void *laddr(const struct dso *p, size_t v) + { + size_t j=0; + if (!p->loadmap) return p->base + v; +- for (j=0; v-p->loadmap->segs[j].p_vaddr >= p->loadmap->segs[j].p_memsz; j++); ++ for (j=0; !fdpic_loadseg_contains_vaddr(&p->loadmap->segs[j], v, ++ j+1 == p->loadmap->nsegs); j++); + return (void *)(v - p->loadmap->segs[j].p_vaddr + p->loadmap->segs[j].addr); + } + static void *laddr_pg(const struct dso *p, size_t v) + { + size_t j=0; + size_t pgsz = PAGE_SIZE; + if (!p->loadmap) return p->base + v; +- for (j=0; ; j++) { +- size_t a = p->loadmap->segs[j].p_vaddr; +- size_t b = a + p->loadmap->segs[j].p_memsz; +- a &= -pgsz; +- b += pgsz-1; +- b &= -pgsz; +- if (v-aloadmap->segs[j], v, pgsz); j++); + return (void *)(v - p->loadmap->segs[j].p_vaddr + p->loadmap->segs[j].addr); + } + static void (*fdbarrier(void *p))() +@@ -875,11 +893,37 @@ + goto error; + } + } +- for (i=0; ((size_t *)(base+dyn))[i]; i+=2) ++ for (i=0; ((size_t *)(base+dyn))[i]; i+=2) + if (((size_t *)(base+dyn))[i]==DT_TEXTREL) { +- if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) +- && errno != ENOSYS) +- goto error; ++ if (DL_FDPIC && dso->loadmap) { ++ size_t seg = 0; ++ ++ if (DL_FDPIC_STRICT_XIP) { ++ errno = ENOTSUP; ++ goto error; ++ } ++ for (ph=ph0, i=eh->e_phnum; i; i--, ++ ph=(void *)((char *)ph+eh->e_phentsize)) { ++ size_t seg_start, seg_len, bias; ++ ++ if (ph->p_type != PT_LOAD) continue; ++ if ((ph->p_flags & PF_X) && !(ph->p_flags & PF_W)) { ++ seg_start = dso->loadmap->segs[seg].addr & -PAGE_SIZE; ++ bias = dso->loadmap->segs[seg].addr - seg_start; ++ seg_len = bias + dso->loadmap->segs[seg].p_memsz; ++ if (seg_len > (size_t)-1 - (PAGE_SIZE-1)) ++ seg_len = (size_t)-1; ++ else ++ seg_len = (seg_len + PAGE_SIZE-1) & -PAGE_SIZE; ++ if (mprotect((void *)seg_start, seg_len, ++ PROT_READ|PROT_WRITE|PROT_EXEC) ++ && errno != ENOSYS) ++ goto error; ++ } ++ seg++; ++ } ++ } else if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) ++ && errno != ENOSYS) goto error; + break; + } + done_mapping: diff --git a/patches/0040-musl-fdpic-laddr-idempotent.patch b/patches/0040-musl-fdpic-laddr-idempotent.patch new file mode 100644 index 0000000..f2250ac --- /dev/null +++ b/patches/0040-musl-fdpic-laddr-idempotent.patch @@ -0,0 +1,21 @@ +diff -uNr musl-patch-old/ldso/dynlink.c musl-patch-new/ldso/dynlink.c +--- musl-patch-old/ldso/dynlink.c ++++ musl-patch-new/ldso/dynlink.c +@@ -205,8 +205,17 @@ + static void *laddr(const struct dso *p, size_t v) + { + size_t j=0; + if (!p->loadmap) return p->base + v; ++ /* Idempotence: if v lies within a segment's runtime range, treat ++ * it as already translated and pass through. This avoids double ++ * translation of function pointers that R_ARM_RELATIVE has already ++ * resolved to runtime addresses (e.g., init_array slots). */ ++ for (j=0; j < p->loadmap->nsegs; j++) { ++ size_t a = p->loadmap->segs[j].addr; ++ if (v >= a && v < a + p->loadmap->segs[j].p_memsz) ++ return (void *)v; ++ } + for (j=0; !fdpic_loadseg_contains_vaddr(&p->loadmap->segs[j], v, + j+1 == p->loadmap->nsegs); j++); + return (void *)(v - p->loadmap->segs[j].p_vaddr + p->loadmap->segs[j].addr); + } diff --git a/scripts/generate-musl-export-map.sh b/scripts/generate-musl-export-map.sh new file mode 100755 index 0000000..0b16573 --- /dev/null +++ b/scripts/generate-musl-export-map.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +set -eu + +if [ "$#" -ne 3 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +CONSUMER_ELF=$1 +PROVIDER_ELF=$2 +OUT=$3 +SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname "$0")" && pwd) +ROOTDIR=$(CDPATH='' cd -- "${SCRIPT_DIR}/.." && pwd) +TARGET=${TARGET:-arm-uclinuxfdpiceabi} +READELF=${READELF:-${ROOTDIR}/toolchain/bin/${TARGET}-readelf} + +[ -x "${READELF}" ] || { + echo "ERROR: missing target readelf: ${READELF}" >&2 + exit 1 +} +[ -f "${CONSUMER_ELF}" ] || { + echo "ERROR: missing consumer ELF: ${CONSUMER_ELF}" >&2 + exit 1 +} +[ -f "${PROVIDER_ELF}" ] || { + echo "ERROR: missing provider ELF: ${PROVIDER_ELF}" >&2 + exit 1 +} + +TMP=${OUT}.tmp + +{ + echo "{" + echo " global:" + { + LC_ALL=C "${READELF}" -Ws "${CONSUMER_ELF}" | + awk ' + $7 != "UND" { next } + $4 != "FUNC" && $4 != "OBJECT" && $4 != "NOTYPE" { next } + $8 == "" { next } + !seen[$8]++ { print $8 } + ' | + sed 's/@.*$//' + + LC_ALL=C "${READELF}" -rW "${PROVIDER_ELF}" | + awk ' + /R_ARM_RELATIVE/ { next } + /R_ARM_NONE/ { next } + /[[:space:]][A-Za-z_][A-Za-z0-9_@.]*$/ { + name = $NF + sub(/@.*/, "", name) + if (name != "" && name != "UND") print name + } + ' + } | + sort -u | + sed 's/^/ /; s/$/;/' + echo " local:" + echo " *;" + echo "};" +} > "${TMP}" + +mv "${TMP}" "${OUT}" diff --git a/scripts/kernel-size-report.sh b/scripts/kernel-size-report.sh index a265965..503987c 100755 --- a/scripts/kernel-size-report.sh +++ b/scripts/kernel-size-report.sh @@ -11,27 +11,112 @@ MODE=${5:-full} TARGET=arm-uclinuxfdpiceabi SIZE_TOOL=${ROOTDIR}/toolchain/bin/${TARGET}-size NM_TOOL=${ROOTDIR}/toolchain/bin/${TARGET}-nm +READELF_TOOL=${ROOTDIR}/toolchain/bin/${TARGET}-readelf SUBSYSTEM_ROLLUP=${ROOTDIR}/scripts/subsystem-rollup.py SUBSYSTEM_BUDGET_CHECK=${ROOTDIR}/scripts/check-subsystem-budget.py SUBSYSTEM_BUDGET_FILE=${ROOTDIR}/configs/subsystem-budget.txt BLOAT_O_METER=${LINUXDIR}/scripts/bloat-o-meter +ROOTFS_DIR=${ROOTDIR}/rootfs mkdir -p "${OUTDIR}" +resolve_rootfs_path() { + path=$1 + depth=${2:-0} + + [ "${depth}" -lt 32 ] || return 1 + [ -e "${path}" ] || [ -L "${path}" ] || return 1 + + if [ -L "${path}" ]; then + target=$(readlink "${path}") + case "${target}" in + /*) + next=${ROOTFS_DIR}${target} + ;; + *) + next=$(dirname "${path}")/${target} + ;; + esac + resolve_rootfs_path "${next}" $((depth + 1)) + return 0 + fi + + readlink -f "${path}" +} + +resolve_runtime_elf() { + name=$1 + + case "${name}" in + /*) + candidate=${ROOTFS_DIR}${name} + resolve_rootfs_path "${candidate}" && return 0 + ;; + esac + + for dir in \ + "${ROOTFS_DIR}/lib" \ + "${ROOTFS_DIR}/usr/lib" \ + "${ROOTDIR}/toolchain/${TARGET}/lib" \ + "${ROOTDIR}/toolchain/${TARGET}/usr/lib"; do + candidate=${dir}/$(basename "${name}") + if [ "${dir#${ROOTFS_DIR}/}" != "${dir}" ]; then + resolve_rootfs_path "${candidate}" && return 0 + elif [ -e "${candidate}" ] || [ -L "${candidate}" ]; then + readlink -f "${candidate}" && return 0 + fi + done + + return 1 +} + +runtime_elf_artifacts() { + [ -x "${READELF_TOOL}" ] || return 0 + [ -f "${ROOTFS_DIR}/bin/busybox" ] || return 0 + + { + LC_ALL=C "${READELF_TOOL}" -l "${ROOTFS_DIR}/bin/busybox" | + sed -n 's/.*Requesting program interpreter: \(.*\)]/\1/p' | + while IFS= read -r interp; do + [ -n "${interp}" ] || continue + resolve_runtime_elf "${interp}" || true + done + + LC_ALL=C "${READELF_TOOL}" -d "${ROOTFS_DIR}/bin/busybox" | + sed -n 's/.*Shared library: \[\(.*\)\]/\1/p' | + while IFS= read -r needed; do + [ -n "${needed}" ] || continue + resolve_runtime_elf "${needed}" || true + done + } | awk 'NF && !seen[$0]++' +} + report_file_sizes() { { echo "artifact bytes" for f in \ "${LINUXDIR}/vmlinux" \ "${LINUXDIR}/arch/arm/boot/Image" \ - "${ROOTDIR}/rootfs/bin/busybox" \ - "${ROOTDIR}/toolchain/${TARGET}/lib/libc.so" \ - "${ROOTDIR}/toolchain/${TARGET}/lib/ld-uClibc.so.0" \ + "${ROOTFS_DIR}/bin/busybox" \ "${BOOTWRAPPERDIR}/linux.axf"; do [ -f "${f}" ] || continue printf '%s %s\n' "${f}" "$(wc -c <"${f}" | tr -d ' ')" done + runtime_elf_artifacts | while IFS= read -r f; do + [ -f "${f}" ] || continue + printf '%s %s\n' "${f}" "$(wc -c <"${f}" | tr -d ' ')" + done + + if [ -d "${ROOTFS_DIR}/lib" ]; then + printf '%s %s\n' "${ROOTFS_DIR}/lib-total" \ + "$(du -sb "${ROOTFS_DIR}/lib" | cut -f1)" + fi + if [ -d "${ROOTFS_DIR}/usr/lib" ]; then + printf '%s %s\n' "${ROOTFS_DIR}/usr/lib-total" \ + "$(du -sb "${ROOTFS_DIR}/usr/lib" | cut -f1)" + fi + if [ -f "${LINUXDIR}/arch/arm/boot/Image" ]; then printf '%s %s\n' "${LINUXDIR}/arch/arm/boot/Image.gz" \ "$(gzip -n -9 -c "${LINUXDIR}/arch/arm/boot/Image" | wc -c | tr -d ' ')" @@ -58,9 +143,16 @@ report_sections() { { for f in \ "${LINUXDIR}/vmlinux" \ - "${ROOTDIR}/rootfs/bin/busybox" \ - "${ROOTDIR}/toolchain/${TARGET}/lib/libc.so" \ - "${ROOTDIR}/toolchain/${TARGET}/lib/ld-uClibc.so.0"; do + "${ROOTFS_DIR}/bin/busybox"; do + [ -f "${f}" ] || continue + echo "== ${f} ==" + if ! "${SIZE_TOOL}" -A "${f}" 2>&1; then + echo "[size tool skipped unsupported file]" + fi + echo + done + + runtime_elf_artifacts | while IFS= read -r f; do [ -f "${f}" ] || continue echo "== ${f} ==" if ! "${SIZE_TOOL}" -A "${f}" 2>&1; then diff --git a/scripts/validate-musl-build.sh b/scripts/validate-musl-build.sh new file mode 100755 index 0000000..00dd12f --- /dev/null +++ b/scripts/validate-musl-build.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +set -eu + +SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname "$0")" && pwd) +ROOTDIR=$(CDPATH='' cd -- "${SCRIPT_DIR}/.." && pwd) +TARGET=${TARGET:-arm-uclinuxfdpiceabi} +TOOLCHAIN=${TOOLCHAIN:-${ROOTDIR}/toolchain} +ROOTFS=${ROOTFS:-${ROOTDIR}/rootfs} +IMAGE=${1:-${ROOTDIR}/bootwrapper/linux.axf} +LOG=${2:-${ROOTDIR}/qemu-musl.log} +WORKLOAD=${3:-${ROOTDIR}/configs/musl-smoke-workload.txt} +METRICS=${4:-${ROOTDIR}/qemu-musl.metrics} +READELF=${READELF:-${TOOLCHAIN}/bin/${TARGET}-readelf} + +BUSYBOX=${ROOTFS}/bin/busybox +LOADER=${ROOTFS}/lib/ld-musl-arm-fdpic.so.1 +LIBC=${ROOTFS}/lib/libc.so + +fail() { + echo "ERROR: $*" >&2 + exit 1 +} + +[ -x "${READELF}" ] || fail "missing target readelf: ${READELF}" +[ -f "${BUSYBOX}" ] || fail "missing rootfs busybox: ${BUSYBOX}" +[ -f "${LIBC}" ] || fail "missing musl libc: ${LIBC}" +[ -L "${LOADER}" ] || fail "missing musl loader symlink: ${LOADER}" +[ -f "${IMAGE}" ] || fail "missing kernel image: ${IMAGE}" +[ -f "${WORKLOAD}" ] || fail "missing workload file: ${WORKLOAD}" + +INTERP=$(LC_ALL=C "${READELF}" -l "${BUSYBOX}" 2>/dev/null | sed -n 's/.*Requesting program interpreter: \(.*\)]/\1/p') +[ "${INTERP}" = "/lib/ld-musl-arm-fdpic.so.1" ] || fail "unexpected PT_INTERP: ${INTERP:-}" + +NEEDED=$( + LC_ALL=C "${READELF}" -d "${BUSYBOX}" 2>/dev/null | + sed -n 's/.*Shared library: \[\(.*\)\]/\1/p' +) +[ -n "${NEEDED}" ] || fail "busybox is missing DT_NEEDED entries" +echo "${NEEDED}" | grep -qx 'libc.so' || fail "busybox does not depend on musl libc" +echo "${NEEDED}" | grep -q 'libuClibc' && fail "busybox still depends on uClibc-ng" + +LOADER_TARGET=$(readlink "${LOADER}" || true) +[ "${LOADER_TARGET}" = "/lib/libc.so" ] || fail "unexpected musl loader symlink target: ${LOADER_TARGET:-}" + +exec "${SCRIPT_DIR}/validate-qemu.sh" "${IMAGE}" "${LOG}" "${WORKLOAD}" "${METRICS}" diff --git a/support/arm-fdpic-crtreloc.c b/support/arm-fdpic-crtreloc.c new file mode 100644 index 0000000..fa22a38 --- /dev/null +++ b/support/arm-fdpic-crtreloc.c @@ -0,0 +1,76 @@ +#include +#include + +#ifdef __FDPIC__ + +struct elf32_fdpic_loadseg { + Elf32_Addr addr; + Elf32_Addr p_vaddr; + Elf32_Word p_memsz; +}; + +struct elf32_fdpic_loadmap { + Elf32_Half version; + Elf32_Half nsegs; + struct elf32_fdpic_loadseg segs[]; +}; + +static inline __attribute__((always_inline)) void *reloc_pointer( + void *p, const struct elf32_fdpic_loadmap *map) +{ + int c; + + for (c = 0; c < map->nsegs && p >= (void *)map->segs[c].p_vaddr; c++) { + unsigned long offset = (char *)p - (char *)map->segs[c].p_vaddr; + if (offset < map->segs[c].p_memsz || + (offset == map->segs[c].p_memsz && c + 1 == map->nsegs)) + return (char *)map->segs[c].addr + offset; + } + + return (void *)-1; +} + +static inline __attribute__((always_inline)) void ***reloc_range_indirect( + void ***p, void ***e, const struct elf32_fdpic_loadmap *map) +{ + while (p < e) { + if (*p != (void **)-1) { + void *ptr = reloc_pointer(*p, map); + if (ptr != (void *)-1) { + void *pt; + if ((long)ptr & 3) { + unsigned char *c = ptr; + int i; + unsigned long v = 0; + for (i = 0; i < 4; i++) + v |= c[i] << (8 * i); + pt = (void *)v; + } else { + pt = *(void **)ptr; + } + pt = reloc_pointer(pt, map); + if ((long)ptr & 3) { + unsigned char *c = ptr; + int i; + unsigned long v = (unsigned long)pt; + for (i = 0; i < 4; i++, v >>= 8) + c[i] = v; + } else { + *(void **)ptr = pt; + } + } + } + p++; + } + return p; +} + +void *__self_reloc(const struct elf32_fdpic_loadmap *map, void ***p, void ***e) +{ + p = reloc_range_indirect(p, e - 1, map); + if (p >= e) + return (void *)-1; + return reloc_pointer(*p, map); +} + +#endif