Debian 提供的 multiarch 功能对于调试跨架构的应用来说非常方便. 尽管 multiarch 常用于在 x86_64 的系统里面运行 x86 的程序.
以下操作以在 x86_64 的系统里面编译并运行 arm64 的应用为示例来演示一下 multiarch.

安装交叉编译的工具链

apt 仓库里面提供了多个架构的 gcc 工具链, 如果编译 arm64 平台的, 可以安装:
$ sudo apt install gcc-aarch64-linux-gnu
该工具包提供了包括编译器和链接器等:
/usr/bin/aarch64-linux-gnu-gcc
/usr/bin/aarch64-linux-gnu-gcc-ar
/usr/bin/aarch64-linux-gnu-gcc-nm
/usr/bin/aarch64-linux-gnu-gcc-ranlib
/usr/bin/aarch64-linux-gnu-gcov
/usr/bin/aarch64-linux-gnu-gcov-dump
/usr/bin/aarch64-linux-gnu-gcov-tool

测试工具链

以下的 hello.c 用于测试 arm64 工具链是否可用:
#include

int _main(_void) {
printf(“Hello, world\n”);
return 0;
}

编译:
$ aarch64-linux-gnu-gcc hello.c -o hello
会生成 hello 文件, 查看一下 hello 这个可执行文件的格式:
$ file hello
hello: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=752dcd6a165921bedbfba81dd8ecba4530bf7c5a, for GNU/Linux 3.7.0, not stripped

安装 qemu

上面生成的 arm64 版的程序, 并不能在我们的 x86_64 系统里直接运行:
$ ./hello
bash: ./hello: cannot execute binary file: Exec format error
但是可以使用 qemu 这个模拟器来运行:
$ sudo apt install qemu-user-static
其中, qemu-user-static 会调用 update-binfmt 命令, 向内核中注册很多 binfmt 格式:

  1. aarch64_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'
  2. aarch64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  3. alpha_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90'
  4. alpha_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  5. arm_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'
  6. arm_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  7. armeb_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28'
  8. armeb_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  9. cris_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x4c\x00'
  10. cris_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  11. hppa_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f'
  12. hppa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  13. i386_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
  14. i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  15. m68k_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04'
  16. m68k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  17. microblaze_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xba\xab'
  18. microblaze_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  19. mips_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'
  20. mips_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  21. mipsel_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'
  22. mipsel_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  23. mips64_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'
  24. mips64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  25. mips64el_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'
  26. mips64el_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  27. ppc_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14'
  28. ppc_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  29. ppc64_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'
  30. ppc64_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  31. ppc64abi32_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'
  32. ppc64abi32_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  33. ppc64le_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00'
  34. ppc64le_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00'
  35. riscv32_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'
  36. riscv32_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  37. riscv64_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'
  38. riscv64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  39. s390x_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16'
  40. s390x_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  41. sh4_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00'
  42. sh4_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  43. sh4eb_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a'
  44. sh4eb_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  45. sparc_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02'
  46. sparc_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  47. sparc32plus_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12'
  48. sparc32plus_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  49. sparc64_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2b'
  50. sparc64_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
  51. x86_64_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'
  52. x86_64_mask='\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  53. xtensa_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e\x00'
  54. xtensa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
  55. xtensaeb_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e'
  56. xtensaeb_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'


这种操作就像 wine 一样, 可以让 linux 系统支持 windows 平台的 PE 格式.
安装好之后, 在终端运行一下:
$ ./hello
/lib/ld-linux-aarch64.so.1: No such file or directory
这里报错的意思是找不到 ld-linux-aarch64.so.1 文件, 该共享库是由 libc6:arm64 包 提供的:
$ sudo apt install libc64:arm64
再次运行一下:
$ ./hello
Hello, world
现在可以运行 arm64 的程序了.

debootstrap 创建隔立的 rootfs

以上演示的, 是在宿主系统中启用 arm64multiarch 的方式来实现的. 但可能会让 宿主系统混乱. 另外这种做法只支持 debian 系的系统.
可以用 debootstrap 创建一个 aarm64 rootfs, 然后 chroot 到这个环境里. 这种做法, 即 qemu + debootstrap 可以运行在大多数 linux 发行版里, 包括那些不支持 multiarch, 不支持 arm64 的系统里.
首先安装 debootstrap:
$ sudo apt install debootstrap
然后创建 arm64 rootfs:
$ sudo debootstrap —arch arm64 buster arm64-rootfs http://ftp.cn.debian.org/debian
以上命令中:

  • —arch arm64, 指定目标架构是 `arm64
  • buster, 指定要安装的版本, 是 debian 10 - buster
  • arm64-rootfs, 指定本地的 rootfs 目录
  • http://ftp.cn.debian.org/debian, 要使用的 apt 仓库地址

经过一段时间的运行, 就会生成 arm64 rootfs:
$ ls arm64-rootfs
bin boot dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
$ file arm64-rootfs/bin/dpkg
arm64-root/bin/dpkg: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=836ed47b5d716f4b5d033975d2dafd8b95ce59c9, stripped
之后, 我们挂载几个目录:
$ cd buster-rootfs
$ sudo mount -t proc proc ./proc
$ sudo mount -t sysfs sysfs ./sys
$ sudo mount —bind /dev ./dev
$ sudo mount -t devpts devpts ./dev/pts
然后 chroot 到这个目录:
$ sudo chroot .
之后就可以在这个 arm64 chroot 环境里正常操作了.

在 arm64 rootfs 里编译 rust 程序

下面我们测试一下在刚刚创建的 rootfs 里面编译一个 rust 程序, 先安装 rust 编译器:
# apt install cargo rustc
之后, 安装一下 fd 命令:
# cargo install fd-find
……………………………….
Compiling regex v1.2.1
Compiling globset v0.4.4
Compiling fd-find v7.3.0
Compiling ignore v0.4.10
Finished release [optimized] target(s) in 9m 26s
Installing /root/.cargo/bin/fd
warning: be sure to add /root/.cargo/bin to your PATH to be able to run the installed binaries
编译速度挺慢的, 等编译完成之后, 就在会 $HOME/.cargo/bin 目录里生成 arm64 版的 fd 可执行文件.

参考