使用 multiarch 运行其它架构的程序
2019-08-26 15:30 linux
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 <stdio.h>
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
格式:
aarch64_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'
aarch64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
alpha_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90'
alpha_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
arm_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'
arm_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
armeb_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28'
armeb_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
cris_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x4c\x00'
cris_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
hppa_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f'
hppa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
i386_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
m68k_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04'
m68k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
microblaze_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xba\xab'
microblaze_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
mips_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'
mips_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
mipsel_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'
mipsel_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
mips64_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'
mips64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
mips64el_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'
mips64el_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xfe\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
ppc_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14'
ppc_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
ppc64_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'
ppc64_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
ppc64abi32_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'
ppc64abi32_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
ppc64le_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00'
ppc64le_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00'
riscv32_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'
riscv32_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
riscv64_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'
riscv64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
s390x_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16'
s390x_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
sh4_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00'
sh4_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
sh4eb_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a'
sh4eb_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
sparc_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02'
sparc_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
sparc32plus_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12'
sparc32plus_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
sparc64_magic='\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2b'
sparc64_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
x86_64_magic='\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'
x86_64_mask='\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
xtensa_magic='\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e\x00'
xtensa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
xtensaeb_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e'
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
以上演示的, 是在宿主系统中启用 arm64
的 multiarch
的方式来实现的. 但可能会让
宿主系统混乱. 另外这种做法只支持 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
可执行文件.
参考
- https://www.instructables.com/id/Uniform-Development-by-Docker-QEMU/
- https://git.savannah.gnu.org/cgit/binfmt-support.git
- https://nongnu.org/binfmt-support/
- https://wiki.debian.org/SupportedArchitectures
- https://wiki.debian.org/Multiarch/HOWTO
- https://www.freedesktop.org/software/systemd/man/binfmt.d.html
- https://en.wikipedia.org/wiki/Binfmt_misc