#1115717 qemu-user-binfmt: fail to execute armhf binaries on arm64 (M1) via binfmt

Package:
qemu-user-binfmt
Source:
qemu-user-binfmt
Description:
QEMU user mode binfmt registration for qemu-user
Submitter:
Andreas Kemnade
Date:
2025-11-16 15:59:01 UTC
Severity:
normal
#1115717#5
Date:
2025-09-19 11:22:02 UTC
From:
To:
Dear Maintainer,

*** Reporter, please consider answering these questions, where appropriate ***

   * What led up to the situation?
installing qemu-user and qemu-binfmt on a m1 Mac
   * What exactly did you do (or not do) that was effective (or
     ineffective)?
$ apt-get download busybox-static:armhf
Get:1 http://deb.debian.org/debian trixie/main armhf busybox-static armhf 1:1.37.0-6+b3 [829 kB]
Fetched 829 kB in 0s (6382 kB/s)
$ dpkg-deb -x busybox-static_1%3a1.37.0-6+b3_armhf.deb .
$ usr/bin/busybox
bash: usr/bin/busybox: cannot execute binary file: Exec format error
$ linux32
linux32: failed to set personality to linux32: Invalid argument
$ qemu-armhf usr/bin/busybox
BusyBox v1.37.0 (Debian 1:1.37.0-6+b3) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.

Usage: busybox [function [arguments]...]
   or: busybox --list[-full]
   or: busybox --install [-s] [DIR]
   or: function [arguments]...

	BusyBox is a multi-call binary that combines many common Unix
	utilities into a single executable.  The shell in this build
	is configured to run built-in utilities without $PATH search.
	You don't need to install a link to busybox for each utility.
	To run external program, use full path (/sbin/ip instead of ip).

Currently defined functions:
	[, [[, acpid, adjtimex, ar, arch, arp, arping, ascii, ash, awk, base64, basename, bc, blkdiscard, blockdev, brctl, bunzip2, busybox, bzcat, bzip2, cal, cat, chgrp, chmod, chown, chroot, chvt, clear, cmp, cp, cpio, crc32, crond, crontab,
	cttyhack, cut, date, dc, dd, deallocvt, depmod, devmem, df, diff, dirname, dmesg, dnsdomainname, dos2unix, dpkg, dpkg-deb, du, dumpkmap, dumpleases, echo, ed, egrep, env, expand, expr, factor, fallocate, false, fatattr, fdisk, fgrep, find,
	findfs, fold, free, freeramdisk, fsfreeze, fstrim, ftpget, ftpput, getfattr, getopt, getty, grep, groups, gunzip, gzip, halt, head, hexdump, hostid, hostname, httpd, hwclock, i2cdetect, i2cdump, i2cget, i2cset, i2ctransfer, id, ifconfig, ifdown,
	ifup, init, insmod, install, ionice, ip, ipcalc, kill, killall, klogd, last, less, link, linux32, linux64, linuxrc, ln, loadfont, loadkmap, logger, login, logname, logread, losetup, ls, lsmod, lsscsi, lzcat, lzma, lzop, md5sum, mdev, microcom,
	mim, mkdir, mkdosfs, mke2fs, mkfifo, mknod, mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount, mt, mv, nameif, nbd-client, nc, netstat, nl, nologin, nproc, nsenter, nslookup, nuke, od, openvt, partprobe, passwd, paste, patch, pidof, ping,
	ping6, pivot_root, poweroff, printf, ps, pwd, rdate, readlink, realpath, reboot, renice, reset, resume, rev, rm, rmdir, rmmod, route, rpm, rpm2cpio, run-init, run-parts, sed, seq, setkeycodes, setpriv, setsid, sh, sha1sum, sha256sum, sha3sum,
	sha512sum, shred, shuf, sleep, sort, ssl_client, start-stop-daemon, stat, strings, stty, su, sulogin, svc, svok, swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar, taskset, tc, tee, telnet, telnetd, test, tftp, time, timeout,
	top, touch, tr, traceroute, traceroute6, true, truncate, ts, tty, tunctl, ubirename, udhcpc, udhcpc6, udhcpd, uevent, umount, uname, uncompress, unexpand, uniq, unix2dos, unlink, unlzma, unshare, unxz, unzip, uptime, usleep, uudecode, uuencode,
	vconfig, vi, w, watch, watchdog, wc, wget, which, who, whoami, xargs, xxd, xz, xzcat, yes, zcat
$

$ ls /proc/sys/fs/binfmt_misc/
llvm-19-runtime.binfmt  qemu-m68k          qemu-or1k     qemu-sparc
python3.13              qemu-microblaze    qemu-ppc      qemu-sparc32plus
qemu-aarch64_be         qemu-microblazeel  qemu-ppc64    qemu-sparc64
qemu-alpha              qemu-mips          qemu-ppc64le  qemu-x86_64
qemu-armeb              qemu-mips64        qemu-riscv32  qemu-xtensa
qemu-hexagon            qemu-mips64el      qemu-riscv64  qemu-xtensaeb
qemu-hppa               qemu-mipsel        qemu-s390x    register
qemu-i386               qemu-mipsn32       qemu-sh4      status
qemu-loongarch64        qemu-mipsn32el     qemu-sh4eb


   * What was the outcome of this action?
directly calling the armhf binary does not work.
   * What outcome did you expect instead?
Being able to run the armhf binary directly without needing to put it into as an
argument to qemu-armhf

Expecting it to work the same way to work as AMD64 binaries:

$ apt-get download busybox-static:amd64
Get:1 http://deb.debian.org/debian trixie/main amd64 busybox-static amd64 1:1.37.0-6+b3 [955 kB]
Fetched 955 kB in 0s (7354 kB/s)
$
$ dpkg-deb -x busybox-static_1%3a1.37.0-6+b3_amd64.deb .
$ usr/bin/busybox
BusyBox v1.37.0 (Debian 1:1.37.0-6+b3) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.

Usage: busybox [function [arguments]...]
   or: busybox --list[-full]
   or: busybox --install [-s] [DIR]
   or: function [arguments]...

	BusyBox is a multi-call binary that combines many common Unix
        utilities into a single executable.  The shell in this build
        is configured to run built-in utilities without $PATH search.
        You don't need to install a link to busybox for each utility.
        To run external program, use full path (/sbin/ip instead of ip).

Currently defined functions:
        [, [[, acpid, adjtimex, ar, arch, arp, arping, ascii, ash, awk, base64, basename, bc, blkdiscard, blockdev, brctl, bunzip2, busybox, bzcat, bzip2, cal, cat, chgrp, chmod, chown, chroot, chvt, clear, cmp, cp, cpio, crc32, crond, crontab,
        cttyhack, cut, date, dc, dd, deallocvt, depmod, devmem, df, diff, dirname, dmesg, dnsdomainname, dos2unix, dpkg, dpkg-deb, du, dumpkmap, dumpleases, echo, ed, egrep, env, expand, expr, factor, fallocate, false, fatattr, fdisk, fgrep, find,
        findfs, fold, free, freeramdisk, fsfreeze, fstrim, ftpget, ftpput, getfattr, getopt, getty, grep, groups, gunzip, gzip, halt, head, hexdump, hostid, hostname, httpd, hwclock, i2cdetect, i2cdump, i2cget, i2cset, i2ctransfer, id, ifconfig, ifdown,
        ifup, init, insmod, install, ionice, ip, ipcalc, kill, killall, klogd, last, less, link, linux32, linux64, linuxrc, ln, loadfont, loadkmap, logger, login, logname, logread, losetup, ls, lsmod, lsscsi, lzcat, lzma, lzop, md5sum, mdev, microcom,
        mim, mkdir, mkdosfs, mke2fs, mkfifo, mknod, mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount, mt, mv, nameif, nbd-client, nc, netstat, nl, nologin, nproc, nsenter, nslookup, nuke, od, openvt, partprobe, passwd, paste, patch, pidof, ping,
        ping6, pivot_root, poweroff, printf, ps, pwd, rdate, readlink, realpath, reboot, renice, reset, resume, rev, rm, rmdir, rmmod, route, rpm, rpm2cpio, run-init, run-parts, sed, seq, setkeycodes, setpriv, setsid, sh, sha1sum, sha256sum, sha3sum,
        sha512sum, shred, shuf, sleep, sort, ssl_client, start-stop-daemon, stat, strings, stty, su, sulogin, svc, svok, swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar, taskset, tc, tee, telnet, telnetd, test, tftp, time, timeout,
        top, touch, tr, traceroute, traceroute6, true, truncate, ts, tty, tunctl, ubirename, udhcpc, udhcpc6, udhcpd, uevent, umount, uname, uncompress, unexpand, uniq, unix2dos, unlink, unlzma, unshare, unxz, unzip, uptime, usleep, uudecode, uuencode,
        vconfig, vi, w, watch, watchdog, wc, wget, which, who, whoami, xargs, xxd, xz, xzcat, yes, zcat
$

#1115717#10
Date:
2025-09-19 14:31:45 UTC
From:
To:
Hi Andreas,

I noticed the same on my Snapdragon X1 Elite based Thinkpad, but
forgot to create a bug report. It can easily be worked around by
creating the necessary symlink manually:

ls -lh /usr/lib/binfmt.d/qemu-arm.conf
lrwxrwxrwx 1 root root 39 13. Sep 09:57 /usr/lib/binfmt.d/qemu-arm.conf -> ../../share/qemu/binfmt.d/qemu-arm.conf

My guess is, that this symlink has not been installed originally,
because arm64 CPUs used to have native support for also running
arm32 instructions. But multiple recent aarch64 CPUs apparently
dropped the compatibility (i.e. Apple M1 and all successors as
well as the Oryon cores used by the Qualcomm Snapdragon X Elite).

Greetings,

#1115717#15
Date:
2025-09-22 15:06:12 UTC
From:
To:
I brought this up the other day on IRC.

Indeed this was given as the reason, or more specifically, that
breaking that support might not be a good idea.

Chris

#1115717#20
Date:
2025-09-22 16:51:00 UTC
From:
To:
On Mon, 22 Sep 2025 17:06:12 +0200 Chris Hofstaedtler <zeha@debian.org> wrote:
maybe that link can be added in post-install if cpu does not support
32bit. If the cpu can do it itself, it is probably faster.

Regards,
Andreas

#1115717#25
Date:
2025-11-16 15:16:35 UTC
From:
To:
debootstrap --arch armhf stable stable-arm32
ends in:

2025-11-16 16:13:15 URL:http://deb.debian.org/debian/pool/main/z/zlib/zlib1g_1.3.dfsg+really1.3.1-1+b1_armhf.deb [75196/75196] -> "/root/stable-arm32//var/cache/apt/archives/partial/zlib1g_1%3a1.3.dfsg+really1.3.1-1+b1_armhf.deb" [1]
/bin/true: error while loading shared libraries: libc.so.6: failed to map segment from shared object


the same line on an amd64 machine just works... so it is more.

Regards,
Andreas