ARM64 主机编译 ImmortalWrt R2S 固件时遇到的 rkbin 问题
上一篇记录了在 Ubuntu 24.04 ARM64 主机上编译 ImmortalWrt 时遇到的 Go bootstrap 问题。
后来又尝试编译 FriendlyARM NanoPi R2S 的固件,结果又碰到了一个 ARM64 编译主机特有的问题。
R2S 使用 Rockchip RK3328,ImmortalWrt 中选择:
Target System: Rockchip
Subtarget: ARMv8
Target Profile: FriendlyARM NanoPi R2S正常配置完成以后开始编译,但是在生成 Rockchip 启动相关文件的时候失败了。
最后发现问题出在 rkbin。
rkbin
Rockchip 平台构建固件的时候会使用到:
rkbin项目地址:
https://github.com/rockchip-linux/rkbin这个仓库里面除了 DDR、BL31 等二进制文件以外,还自带了一些编译过程中需要执行的工具。
问题是这些工具并不是根据当前 Build Host 编译出来的,而是 Rockchip 直接提供的预编译程序。
其中部分工具是:
x86_64而我的编译主机是:
Ubuntu 24.04 ARM64所以编译过程中执行这些工具时会失败。
类似:
cannot execute binary file: Exec format error以 loaderimage 为例,可以先找到它的位置:
find ./ -name 'loaderimage'在我的编译目录中会看到:
./staging_dir/target-aarch64_generic_musl/image/loaderimage
./build_dir/target-aarch64_generic_musl/rkbin-rk3328/rkbin-2025.06.13~74213af1/tools/loaderimage其中 build_dir 下面这个就是 rkbin 包中自带的工具。
因为 rkbin 的版本以后可能会变化,所以后面直接用通配符来检查:
file ./build_dir/target-aarch64_generic_musl/rkbin-rk3328/*/tools/loaderimage可以看到类似:
ELF 64-bit LSB executable, x86-64这里需要区分一下 Target 和 Build Host。
虽然 R2S 本身也是 ARM64:
Build Host: ARM64
Target: ARM64但是编译过程中使用的 rkbin 工具却是:
rkbin Tool: x86_64所以真正的问题不是生成的 R2S 固件架构,而是 ARM64 编译主机无法直接执行 x86_64 的 Host Tool。
使用 QEMU
解决方法是使用 QEMU user mode 来运行这些 x86_64 程序。
安装:
sudo apt update
sudo apt install qemu-user-static上一篇安装编译环境的时候已经安装过:
qemu-utils不过 qemu-utils 和这里不是一回事。
这里需要的是:
qemu-user-static安装完成后可以确认:
which qemu-x86_64-static正常可以看到:
/usr/bin/qemu-x86_64-static不过只安装这个还不够。
QEMU_LD_PREFIX
最开始我安装完 qemu-user-static 以后,编译仍然有问题。
最后还需要设置:
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu原因是 rkbin 里面的一些 x86_64 工具并不是完全静态链接的程序。
它们运行时还需要 x86_64 的动态链接器以及对应的运行库。
但是当前系统本身是 ARM64,所以系统默认的 /lib 和 /usr/lib 中主要是 ARM64 的库。
需要通过:
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu告诉 QEMU 去哪里寻找 x86_64 的运行环境。
例如 x86_64 ELF 通常需要:
/lib64/ld-linux-x86-64.so.2设置 QEMU_LD_PREFIX 以后,QEMU 会去类似下面的位置寻找:
/usr/x86_64-linux-gnu/lib64/ld-linux-x86-64.so.2上一篇为了在 ARM64 主机上编译 ImmortalWrt,已经安装过:
sudo apt install gcc-x86-64-linux-gnu g++-x86-64-linux-gnu所以:
/usr/x86_64-linux-gnu这套 x86_64 cross sysroot 已经存在,可以直接使用。
最终需要的就是:
sudo apt install qemu-user-static
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu如果以后经常在这台机器上编译,也可以直接加入:
~/.bashrc例如:
echo 'export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu' >> ~/.bashrc
source ~/.bashrcbinfmt
Ubuntu 安装 qemu-user-static 后,可以通过 Linux 的 binfmt_misc 自动处理其它架构的 ELF。
检查:
ls /proc/sys/fs/binfmt_misc/可以看看有没有:
qemu-x86_64也可以:
cat /proc/sys/fs/binfmt_misc/qemu-x86_64如果已经注册,那么编译系统执行 rkbin 中的 x86_64 工具时,不需要专门改成:
qemu-x86_64-static ./loaderimage系统会自动调用 QEMU。
而:
export QEMU_LD_PREFIX=/usr/x86_64-linux-gnu则负责让 QEMU 找到对应的 x86_64 loader 和运行库。
简单来说就是:
ARM64 Ubuntu
|
v
binfmt_misc
|
v
qemu-x86_64
|
| QEMU_LD_PREFIX
v
/usr/x86_64-linux-gnu
|
v
rkbin x86_64 Tool这样对于 ImmortalWrt 自己的 Makefile 来说基本是透明的,不需要修改 rkbin,也不需要修改编译脚本。
验证
这里主要检查 build_dir 里面 rkbin 自带的原始工具:
file ./build_dir/target-aarch64_generic_musl/rkbin-rk3328/*/tools/loaderimage确认它是:
x86-64然后直接运行测试:
./build_dir/target-aarch64_generic_musl/rkbin-rk3328/*/tools/loaderimage如果不再出现:
Exec format error而是能够正常输出程序自己的参数或者错误提示,说明 QEMU 已经可以正常执行这个 x86_64 程序了。
staging_dir 里面也会有一个:
./staging_dir/target-aarch64_generic_musl/image/loaderimage这是构建过程中放到 staging area 中的版本,这里主要确认 build_dir 中 rkbin 包自带的工具能够正常运行即可。
之后重新编译:
make V=s -j1确认能够通过之前失败的位置以后,再恢复正常并行编译:
make V=s -j$(nproc)之后 R2S 固件就可以正常生成了。