Skip to content

Houdini: run Arm 32-bit and 64-bit applications on an x86_64 system

Intel Houdini is a dynamic binary translation layer to run Arm applications on x86_64 systems. Its targeted platform is Android, but you can use it for _other_ platforms too. It’s much faster than Qemu at that task.

Houdini 6 with AArch64 on x86_64 compatibility is available at http://dl.android-x86.org/houdini/6_z/houdini.sfs and for AArch32 on x86_64 at http://dl.android-x86.org/houdini/6_y/houdini.sfs.

The patch function at https://everydaywithlinux.blogspot.com/2012/11/patch-strings-in-binary-files-with-sed.html will be used here.

mkdir arm64_x64
mkdir armv7_x64
unsquashfs houdini-6_z.sfs
cp squashfs-root/houdini64 arm64_x64/
cp squashfs-root/cpuinfo arm64_x64/
cp squashfs-root/linker64 arm64_x64/
rm -rf squashfs-root

unsquashfs houdini-6_y.sfs
cp squashfs-root/houdini armv7_x64/
cp squashfs-root/cpuinfo armv7_x64/
cp squashfs-root/linker armv7_x64/
rm -rf squashfs-root

First, the SquashFS image that Houdini ships in is unpacked.

patch_strings_in_file arm64_x64/houdini64 "/system/lib64/arm64/cpuinfo" "/usr/lib/houdini/cpu64"
patch_strings_in_file arm64_x64/houdini64 "/system/lib64/arm64/linker64" "/lib/ld-linux-aarch64.so.1"
patch_strings_in_file arm64_x64/houdini64 "/system/lib64/arm64/libaeabi_map.so" ""

patch_strings_in_file armv7_x64/houdini "/system/lib/arm/cpuinfo" "/usr/lib/houdini/cpu32"
patch_strings_in_file armv7_x64/houdini "/system/lib/arm/linker" "/usr/lib/houdini/ld.so"
patch_strings_in_file armv7_x64/houdini "/system/lib/arm/libaeabi_map.so" ""

Then, patches are made, note here that we patched the library loader path to /usr/lib/houdini/ld.so for 32-bit Arm binaries, that’s because we don’t have enough bytes to put in the full path.

:arm_exe:M::\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28::/usr/libexec/houdini:POC
:armv7_exe:M::\x7f\x45\x4c\x46\x01\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28::/usr/libexec/houdini:POC
:arm64_exe:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7::/usr/libexec/houdini64:POC
:arm64_exe_2:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\xb7::/usr/libexec/houdini64:POC
:arm64_exe_3:M::\x7f\x45\x4c\x46\x02\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7::/usr/libexec/houdini64:POC

That’s the content of the houdini.conf file that’ll be used by binfmt_misc to redirect the attempts to run Arm applications to Houdini.

mkdir -p /usr/libexec
install -m 755 arm64_x64/houdini64 $DESTDIR/usr/libexec/houdini64
install -m 755 armv7_x64/houdini $DESTDIR/usr/libexec/houdini

mkdir -p /usr/lib/houdini
install -m 644 arm64_x64/cpuinfo $DESTDIR/usr/lib/houdini/cpu64
install -m 644 armv7_x64/cpuinfo $DESTDIR/usr/lib/houdini/cpu32
ln -s /lib/ld-linux-armhf.so.3 $DESTDIR/usr/lib/houdini/ld.so

mkdir -p /etc/binfmt.d
install -m 644 houdini.conf $DESTDIR/etc/binfmt.d/houdini.conf

systemctl restart systemd-binfmt.service

You can then install to your system this way, or by making a proper package. (to run as root)

You’ll then have to copy over those files to the Arm chroot that your distribution will run in too. For 32-bit Arm, it’s also needed to link /usr/lib/houdini/ld.so to your library loader.

You can then set the bind mounts to /sys, /dev, /dev/pts and /proc. Afterwards, you can chroot and use the Arm environment.

In case of Linux distributions using the musl C library, you’ll have to link /lib/ld-linux-armhf.so.3 and /lib/ld-linux-aarch64.so.1 to your libc path for the architecture. (on musl, the C library and the library loader are the same executable)

Note: If you try to access to the TPIDRURW MSR when using Houdini running a 32-bit Arm application, you’ll get a crash. This MSR is only used in practice when using Wine to run a 32-bit Arm Windows app.

4 thoughts on “Houdini: run Arm 32-bit and 64-bit applications on an x86_64 system”

  1. Hello
    I would like to change from qemu-aarch64-static to houdini. I use qemu-aarch64-static with a chroot and this works but it is slow. Host System Ubuntu 22.04 Chroot System Debian Buster

    unsquashfs worked.
    patch_strings_in_file worked.
    binfmt.d/houdini.conf worked.

    My question is:
    What is $DESTDIR. On my system, this variable is empty so it installs it on /usr/libexec/ and /usr/lib/houdini/. Is that correct?
    And do I have to copy some of the files houdini64 or cpu64 or linker64 into the chroot?

    Thanks in advice
    Andreas Odermatt

    1. > And do I have to copy some of the files houdini64 or cpu64 or linker64 into the chroot?

      Yes (for houdini64 and cpu64)

      For linker64, you should link that to the path of the linker inside of the guest chroot.

  2. Thank you very much. Everything works now with aarch64. Its 3 times faster then qemu.
    With armhf, I have a problem.

    Wenn I am in the chroot and compile with g++, i get the error
    collect2: fatal error: ld terminated with signal 11 [Segmentation fault]
    compilation terminated.
    Its every time when the linker is called.
    ldd –version
    ldd (Debian GLIBC 2.28-10+deb10u1) 2.28

    Everything else works. Do you have an idea, what the problem could be? Something with TPIDRURW? In aarch64 the compile of the program works.

    Thank you very much.

    1. Nothing to do with TPIDRURW, which is only used/applicable to ARMv7 Windows, and is not typically used by Linux software. Might be worth debugging more.. or not. Wonder if this might be fixed in a later Houdini release…

Leave a Reply

Your email address will not be published. Required fields are marked *