Search code examples
linuxqemu

How can QEMU dynamically switch from aarch64 to x86 based on the ELF I'm executing?


I have an aarch64 image that I've extracted to a folder on my x86 Linux host. I perform the following procedure using QEMU version 6.2:

image_root@user$ qemu-aarch64 -L $PWD ./bin/bash.bash
I have no name!@user:/path/to/image_root$ sudo chroot . ./bin/bash.bash
[sudo] password for user:
bash.bash-5.0#

The shell I end up in is the aarch64 version of bash from the image, which is what I wanted (Yey!).

My question is how could I run both the x86_64 chroot and the aarch64 bash.bash from inside the same QEMU emulation?

My guess is QEMU is dynamically switching from X86_64 and aarch64 depending on the ELF, but It's just a guess and I couldn't find anything about that from a quick browse of the docs.

I know that procedure doesn't work on QEMU version 5.2 and lower, and I'm trying to integrate it into an automation I'm doing, so I'd really like to know what's going on.


Solution

  • This works because of the host kernel's binfmt-misc support. This is a flexible way that you can configure the kernel to say "if somebody tries to execute a file which matches this pattern, the way to do that is to run some other program and pass it the file".

    When a distro package version of QEMU is installed, the packaging typically also takes care of registering QEMU with the binfmt-misc handling, so that if you try to execute an AArch64 ELF file then the kernel knows that it must run it by running qemu-aarch64 and passing the ELF file.

    Within QEMU itself the exec() system call is not handled specially -- we just pass it to the host kernel.

    Put together, this means that if you try to execute an x86 binary, the kernel runs it directly, and if you try to execute an aarch64 binary, the kernel passes it to QEMU. And this happens whether the "try to execute" started from an x86 program or from an aarch64 program run under QEMU.