From 028db19eded36d6cec66dfcad9025cbae754f9d9 Mon Sep 17 00:00:00 2001 From: Dmitry Ilyin <6576495+widgetii@users.noreply.github.com> Date: Mon, 18 May 2026 13:01:47 +0300 Subject: [PATCH] glibc-compat: add static-link mmap shim for vendor 32-bit off_t blobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vendor glibc binaries from the V2 era (e.g. hi3520dv200's libmpi.so) were built without _FILE_OFFSET_BITS=64 so their mmap() takes a 32-bit off_t. musl's mmap() exports 64-bit off_t — when libmpi dynamic-links against musl on a modern rootfs, the high 32 bits of the offset arg come from uninitialised stack and the kernel sees a garbage pgoff, rejecting with EINVAL. Symptom on hi3520dv200: every HI_MPI_VENC_CreateChn returns 0xa007800c (EN_ERR_VENC_NOMEM) because libmpi can't mmap the model_buf via /dev/venc. Confirmed via LD_PRELOAD trace shim that wraps mmap(): the syscall reaches the kernel with off=0x402b65d8 — a userspace VA (varies between runs with ASLR), clearly stack garbage. Fix: add glibc-compat-static.c with a 32-bit off_t mmap()/mmap64() wrapper that goes straight to SYS_mmap2 bypassing musl's libc wrapper. Same pattern as #2000 (uclibc-compat-static for hi3516cv100). The function must be statically linked into the consumer executable (not in a .so) so the dynamic linker resolves vendor .so imports of mmap to the executable's symbol table BEFORE musl — putting it in a .so would override musl process-wide and break musl's own internal mmap callers (malloc, dlopen, etc.). - glibc-compat/src/glibc-compat-static.c: new file, mmap()/mmap64() wrappers calling SYS_mmap2 with pgoff - glibc-compat/src/Makefile: build both libglibc-compat.so and libglibc-compat-static.a - glibc-compat/glibc-compat.mk: INSTALL_STAGING=YES, install .a to STAGING_DIR so dependent packages can link -lglibc-compat-static - Makefile (BUNDLE_SDK): produce libglibc-compat.so and libglibc-compat-static.a in the published toolchain SDK tarball, mirroring the existing uclibc-compat handling Verified on lab DVR (openipc-hi3520dv200.dlab.torturelabs.com): linking dvr_home with the mmap shim makes HI_MPI_VENC_CreateChn succeed on all 4 channels. Refs: #1992 (toolchain ABI audit), #1993 (cv100 stat shim), #2000 (cv100 static-link split) --- Makefile | 35 ++++++++++++---- general/package/glibc-compat/glibc-compat.mk | 6 +++ general/package/glibc-compat/src/Makefile | 10 ++++- .../glibc-compat/src/glibc-compat-static.c | 41 +++++++++++++++++++ 4 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 general/package/glibc-compat/src/glibc-compat-static.c diff --git a/Makefile b/Makefile index 088dfc24ac..015d0cd419 100644 --- a/Makefile +++ b/Makefile @@ -119,7 +119,10 @@ define BUNDLE_SDK OSDRV_DIR=$(PWD)/general/package/$(BR2_OPENIPC_SOC_VENDOR)-osdrv-$(BR2_OPENIPC_SOC_FAMILY)/files; \ MPP_HEADERS=$(PWD)/general/package/hisilicon-osdrv-hi3516cv100/files/include; \ SDK_TGZ=$$(find $(TARGET)/images -name '*_sdk-buildroot.tar.gz' | head -1); \ - COMPAT_SRC=$(PWD)/general/package/uclibc-compat/src/uclibc-compat.c; \ + UCLIBC_COMPAT_SRC=$(PWD)/general/package/uclibc-compat/src/uclibc-compat.c; \ + UCLIBC_COMPAT_STATIC=$(PWD)/general/package/uclibc-compat/src/uclibc-compat-static.c; \ + GLIBC_COMPAT_SRC=$(PWD)/general/package/glibc-compat/src/glibc-compat.c; \ + GLIBC_COMPAT_STATIC=$(PWD)/general/package/glibc-compat/src/glibc-compat-static.c; \ SDK_CC=$$(ls $(TARGET)/host/bin/*-gcc 2>/dev/null | head -1); \ if [ -d "$$OSDRV_DIR" ] && [ -n "$$SDK_TGZ" ]; then \ SDK_TOP=$$(tar tzf $$SDK_TGZ | head -1 | cut -d/ -f1); \ @@ -129,20 +132,34 @@ define BUNDLE_SDK mkdir -p /tmp/sdk-overlay/$$SDK_TOP/sdk/include; \ cp -a $$MPP_HEADERS/. /tmp/sdk-overlay/$$SDK_TOP/sdk/include/; \ fi; \ - if [ -f "$$COMPAT_SRC" ] && [ -n "$$SDK_CC" ]; then \ - $$SDK_CC -shared -Wall -O2 -fPIC \ - -o /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/libuclibc-compat.so \ - $$COMPAT_SRC; \ - COMPAT_STATIC=$(PWD)/general/package/uclibc-compat/src/uclibc-compat-static.c; \ - if [ -f "$$COMPAT_STATIC" ]; then \ - SDK_AR=$$(echo $$SDK_CC | sed 's/-gcc$$/-ar/'); \ + if [ -n "$$SDK_CC" ]; then \ + SDK_AR=$$(echo $$SDK_CC | sed 's/-gcc$$/-ar/'); \ + if [ -f "$$UCLIBC_COMPAT_SRC" ]; then \ + $$SDK_CC -shared -Wall -O2 -fPIC \ + -o /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/libuclibc-compat.so \ + $$UCLIBC_COMPAT_SRC; \ + fi; \ + if [ -f "$$UCLIBC_COMPAT_STATIC" ]; then \ $$SDK_CC -Wall -O2 -fPIC -c \ -o /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/uclibc-compat-static.o \ - $$COMPAT_STATIC; \ + $$UCLIBC_COMPAT_STATIC; \ $$SDK_AR rcs /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/libuclibc-compat-static.a \ /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/uclibc-compat-static.o; \ rm -f /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/uclibc-compat-static.o; \ fi; \ + if [ -f "$$GLIBC_COMPAT_SRC" ]; then \ + $$SDK_CC -shared -Wall -O2 -fPIC \ + -o /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/libglibc-compat.so \ + $$GLIBC_COMPAT_SRC; \ + fi; \ + if [ -f "$$GLIBC_COMPAT_STATIC" ]; then \ + $$SDK_CC -Wall -O2 -fPIC -c \ + -o /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/glibc-compat-static.o \ + $$GLIBC_COMPAT_STATIC; \ + $$SDK_AR rcs /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/libglibc-compat-static.a \ + /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/glibc-compat-static.o; \ + rm -f /tmp/sdk-overlay/$$SDK_TOP/sdk/lib/glibc-compat-static.o; \ + fi; \ fi; \ gunzip $$SDK_TGZ && \ tar rf $${SDK_TGZ%.tar.gz}.tar -C /tmp/sdk-overlay $$SDK_TOP && \ diff --git a/general/package/glibc-compat/glibc-compat.mk b/general/package/glibc-compat/glibc-compat.mk index cbc9ac0bf7..13cbef4684 100644 --- a/general/package/glibc-compat/glibc-compat.mk +++ b/general/package/glibc-compat/glibc-compat.mk @@ -7,6 +7,7 @@ GLIBC_COMPAT_VERSION = GLIBC_COMPAT_SITE = GLIBC_COMPAT_LICENSE = MIT +GLIBC_COMPAT_INSTALL_STAGING = YES define GLIBC_COMPAT_BUILD_CMDS $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(GLIBC_COMPAT_PKGDIR)/src all @@ -17,6 +18,11 @@ endef # pointing all four names at it is enough for the loader to satisfy NEEDED # entries; the libglibc-compat.so providing missing symbols is pulled in by # the LD_PRELOAD-equivalent NEEDED added to vendor wrapper scripts. +define GLIBC_COMPAT_INSTALL_STAGING_CMDS + $(INSTALL) -D -m 0644 $(GLIBC_COMPAT_PKGDIR)/src/libglibc-compat-static.a \ + $(STAGING_DIR)/usr/lib/libglibc-compat-static.a +endef + define GLIBC_COMPAT_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 $(GLIBC_COMPAT_PKGDIR)/src/libglibc-compat.so \ $(TARGET_DIR)/usr/lib/libglibc-compat.so diff --git a/general/package/glibc-compat/src/Makefile b/general/package/glibc-compat/src/Makefile index b3783a4510..969684ee20 100644 --- a/general/package/glibc-compat/src/Makefile +++ b/general/package/glibc-compat/src/Makefile @@ -1,10 +1,16 @@ CFLAGS ?= -O2 CFLAGS += -Wall -fPIC -all: libglibc-compat.so +all: libglibc-compat.so libglibc-compat-static.a libglibc-compat.so: glibc-compat.c $(CC) $(CFLAGS) -shared -o $@ $^ +libglibc-compat-static.a: glibc-compat-static.o + $(AR) rcs $@ $^ + +glibc-compat-static.o: glibc-compat-static.c + $(CC) $(CFLAGS) -c -o $@ $< + clean: - rm -f *.o *.so + rm -f *.o *.so *.a diff --git a/general/package/glibc-compat/src/glibc-compat-static.c b/general/package/glibc-compat/src/glibc-compat-static.c new file mode 100644 index 0000000000..4177697046 --- /dev/null +++ b/general/package/glibc-compat/src/glibc-compat-static.c @@ -0,0 +1,41 @@ +/* + * glibc-compat-static.c -- ABI wrappers that MUST be statically linked + * + * Vendor glibc binaries built against 32-bit off_t (no _FILE_OFFSET_BITS=64, + * typical of 2014-era SDKs like Hi3520DV200's MPP) call mmap() with a + * single-register 32-bit offset arg. musl's mmap() expects 64-bit off_t — + * when the vendor .so binds against musl, the kernel sees uninitialised + * stack as the high half of pgoff and rejects with EINVAL. Symptom on + * hi3520dv200: VENC CreateChn returns 0xa007800c (EN_ERR_VENC_NOMEM) + * because libmpi can't mmap the model_buf via /dev/venc. + * + * This function MUST be linked statically into the EXECUTABLE + * (-lglibc-compat-static) so it appears in the executable's symbol + * table. The dynamic linker then resolves vendor .so imports from the + * executable BEFORE musl. Putting it in a shared library would override + * musl's mmap process-wide, breaking musl's own internal mmap callers + * (malloc, dlopen, ...). + * + * Pattern mirrors OpenIPC/firmware#2000 (uclibc-compat-static for the + * hi3516cv100 vendor blobs). + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#ifndef SYS_mmap2 +#define SYS_mmap2 192 +#endif + +void *mmap(void *addr, size_t len, int prot, int flags, int fd, uint32_t offset) +{ + return (void *)syscall(SYS_mmap2, addr, len, prot, flags, fd, offset >> 12); +} + +void *mmap64(void *addr, size_t len, int prot, int flags, int fd, uint32_t offset) +{ + return (void *)syscall(SYS_mmap2, addr, len, prot, flags, fd, offset >> 12); +}