QEMU and Dynamic Linking on Ubuntu

How to install shared libraries from other architectures.

As part of my recent adventures in cross-compilation using Zig, I've been using QEMU extensively to test cross-compiled binaries.

One issue I ran into is this:

$ zig cc -target aarch64-linux-gnu main.c
$ wsl qemu-aarch64 ./a.out
/lib/ld-linux-aarch64.so.1: No such file or directory

Makes sense, really. It's a dynamically-linked executable (note the -gnu rather than -musl) and there's no particular reason that you'd expect the dynamic linker for another architecture to be present.

It turns out that you actually can install the dynamic linker (or, to be precise, the libc) from other architectures. The process is not documented very well, though.

First, run the following:

# dpkg --add-architecture arm64

Next, you'll need to modify your /etc/apt/sources.list (or files in /etc/apt/sources.list.d depending on how you've organized things). In my case, it looked like this:

deb http://archive.canonical.com/ubuntu groovy partner
deb http://archive.ubuntu.com/ubuntu groovy main multiverse restricted universe
deb http://archive.ubuntu.com/ubuntu groovy-backports main multiverse restricted universe
deb http://archive.ubuntu.com/ubuntu groovy-updates main multiverse restricted universe
deb http://security.ubuntu.com/ubuntu groovy-security main multiverse restricted universe

Most of these repositories don't actually have an arm64 port. So you'll need to decorate them like so:

deb http://archive.canonical.com/ubuntu groovy partner
deb [arch=amd64] http://archive.ubuntu.com/ubuntu groovy main multiverse restricted universe
deb [arch=amd64] http://archive.ubuntu.com/ubuntu groovy-backports main multiverse restricted universe
deb [arch=amd64] http://archive.ubuntu.com/ubuntu groovy-updates main multiverse restricted universe
deb [arch=amd64] http://security.ubuntu.com/ubuntu groovy-security main multiverse restricted universe

This prevents apt from fetching from these repositories for architectures other than amd64.

Next, you'll need to add the actual arm64 repositories to the file:

deb [arch=arm64] http://ports.ubuntu.com groovy main multiverse restricted universe
deb [arch=arm64] http://ports.ubuntu.com groovy-backports main multiverse restricted universe
deb [arch=arm64] http://ports.ubuntu.com groovy-updates main multiverse restricted universe

Now, make sure everything's updated:

# apt update && apt dist-upgrade

Now you can install libc:

# apt install libc6:arm64

And finally:

$ wsl qemu-aarch64 ./a.out
Hello World

Note: If you're like me and also care about armhf, you can change the [arch=arm64] to [arch=arm64,armhf] in your /etc/apt/sources.list and repeat all the other steps, replacing arm64 with armhf.