在 Android ARM64 上运行 x86_64 程序
在 Android ARM64 上运行 x86_64 程序
概述
本文档介绍如何在 Android ARM64 系统上通过 QEMU 用户模式模拟和 binfmt_misc 机制,实现"无感"运行 x86_64 二进制程序。配置完成后,可以直接执行 x86_64 程序,系统会自动调用 QEMU 进行模拟执行。
需要的组件
1. QEMU 二进制文件
需要 qemu-x86_64-static 的 ARM64 版本,用于在 ARM64 架构上模拟执行 x86_64 指令。
获取方式:
- 从 Debian/Ubuntu 的
qemu-user-static包中提取 - 路径:
/usr/bin/qemu-x86_64-static - 确保是静态链接版本(
-static),更适合嵌入式环境
2. binfmt_misc 配置
需要在内核中注册 x86_64 二进制格式,让系统自动识别并调用 QEMU。
系统要求:
- 内核支持
CONFIG_BINFMT_MISC - 已挂载
binfmt_misc文件系统 - Root 权限(配置 binfmt_misc 需要 root)
配置步骤
步骤 1:挂载 binfmt_misc(如果未挂载)
# 检查是否已挂载
ls /proc/sys/fs/binfmt_misc/# 如果不存在 register 和 status 文件,需要挂载
mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
步骤 2:安装 QEMU 二进制文件
将 qemu-x86_64-static 复制到 Android 系统的合适位置,例如:
# 复制到系统目录(需要 root)
cp qemu-x86_64-static /system/bin/qemu-x86_64-static
chmod 755 /system/bin/qemu-x86_64-static# 或者复制到数据目录
cp qemu-x86_64-static /data/local/tmp/qemu-x86_64-static
chmod 755 /data/local/tmp/qemu-x86_64-static
步骤 3:注册 binfmt_misc 配置
使用以下命令注册 x86_64 二进制格式:
# 方式 1:直接使用 qemu-x86_64-static 作为解释器
echo ':qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/system/bin/qemu-x86_64-static:OPF' > /proc/sys/fs/binfmt_misc/register# 方式 2:如果使用 /data/local/tmp 路径
echo ':qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/data/local/tmp/qemu-x86_64-static:OPF' > /proc/sys/fs/binfmt_misc/register
配置参数说明:
- name:
qemu-x86_64- 标识符名称 - type:
M- 使用魔数(magic)匹配 - magic:
\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00\x7f\x45\x4c\x46= ELF 文件头(\x7fELF)\x02= 64位 ELF\x01= 小端序\x3e=EM_X86_64(x86_64 架构代码,十进制 62)\x02= 可执行文件类型(ET_EXEC)
- mask:
\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff- 掩码,用于匹配时忽略某些位 - interpreter:
/system/bin/qemu-x86_64-static- QEMU 解释器路径 - flags:
OPFO= 打开二进制文件P= 保留(preserve)F= 修复二进制文件(fix binary)
步骤 4:验证配置
# 查看注册的格式
ls /proc/sys/fs/binfmt_misc/# 查看 x86_64 配置详情
cat /proc/sys/fs/binfmt_misc/qemu-x86_64
预期输出:
enabled
interpreter /system/bin/qemu-x86_64-static
flags: OPF
offset 0
magic 7f454c4602010100000000000000000002003e00
mask fffffffffffffefe00fefffffffffffffeffffff
步骤 5:测试运行
# 测试运行 x86_64 程序
./your_x86_64_program
静态链接 vs 动态链接
静态链接程序
可以直接运行! 配置完成后,静态链接的 x86_64 程序可以直接执行:
# 编译静态链接程序(在 x86_64 系统上)
gcc -static -o program program.c# 在 Android ARM64 上直接运行
./program
动态链接程序
动态链接的程序需要额外的 x86_64 动态库支持。有两种解决方案:
方案 A:使用包装脚本
创建一个包装脚本,自动添加 -L 参数指定库路径:
#!/system/bin/sh
# wrapper script: /system/bin/qemu-x86_64-wrapper
exec /system/bin/qemu-x86_64-static -L /path/to/x86_64-libs "$@"
然后在 binfmt_misc 中注册包装脚本:
echo ':qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/system/bin/qemu-x86_64-wrapper:OPF' > /proc/sys/fs/binfmt_misc/register
方案 B:手动指定库路径
如果不想使用包装脚本,可以手动运行:
qemu-x86_64-static -L /path/to/x86_64-libs ./dynamic_program
注意: 需要准备完整的 x86_64 动态库环境(libc.so、ld-linux-x86-64.so.2 等)。
持久化配置
如果需要在系统启动时自动配置,可以创建一个 init 脚本。参考 android_binfmt_misc.md 中的方法,在系统启动脚本中添加配置命令。
示例(添加到 init.rc 或类似的启动脚本):
# 在系统启动时挂载 binfmt_misc
mount binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc# 注册 x86_64 格式
write /proc/sys/fs/binfmt_misc/register ":qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/system/bin/qemu-x86_64-static:OPF"
参考配置
从 qemu-user-static deb 包中提取的标准配置:
Systemd 风格配置 (/usr/lib/binfmt.d/qemu-x86_64.conf):
:qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/libexec/qemu-binfmt/x86_64-binfmt-P:OPF
传统风格配置 (/usr/share/binfmts/qemu-x86_64):
package qemu-user-static
interpreter /usr/libexec/qemu-binfmt/x86_64-binfmt-P
magic \x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00
offset 0
mask \xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff
credentials no
fix_binary yes
preserve yes
注意事项
- 性能影响:QEMU 用户模式模拟会有性能损失,不适合 CPU 密集型任务
- Root 权限:配置 binfmt_misc 需要 root 权限
- 动态库依赖:动态链接程序需要完整的 x86_64 库环境
- 系统调用兼容性:某些系统调用可能无法完全模拟,特别是 Android 特有的系统调用
- 文件路径:确保 QEMU 二进制文件的路径正确,且具有执行权限
故障排查
问题 1:无法识别 x86_64 程序
# 检查 binfmt_misc 是否已挂载
ls /proc/sys/fs/binfmt_misc/# 检查配置是否存在
cat /proc/sys/fs/binfmt_misc/qemu-x86_64# 检查配置是否启用
echo 1 > /proc/sys/fs/binfmt_misc/qemu-x86_64 # 启用
问题 2:QEMU 无法找到
# 检查 QEMU 文件是否存在
ls -l /system/bin/qemu-x86_64-static# 检查执行权限
chmod 755 /system/bin/qemu-x86_64-static# 手动测试 QEMU
/system/bin/qemu-x86_64-static --version
问题 3:动态链接程序无法运行
# 检查程序依赖
file your_program
readelf -d your_program | grep NEEDED# 手动指定库路径运行
qemu-x86_64-static -L /path/to/x86_64-libs ./your_program
问题 4:Root 用户无法写入 register 文件
即使有 root 权限,也可能无法写入 /proc/sys/fs/binfmt_misc/register。可能的原因和解决方案:
检查 1:确认 binfmt_misc 已挂载
# 检查是否已挂载
ls /proc/sys/fs/binfmt_misc/# 如果 register 文件不存在,需要先挂载
mount -t binfmt_misc none /proc/sys/fs/binfmt_misc# 验证挂载
mount | grep binfmt_misc
检查 2:确认内核支持 binfmt_misc
# 检查内核配置(如果可访问)
grep CONFIG_BINFMT_MISC /proc/config.gz
# 或者
zcat /proc/config.gz | grep CONFIG_BINFMT_MISC# 应该显示:CONFIG_BINFMT_MISC=y 或 CONFIG_BINFMT_MISC=m
检查 3:SELinux 限制(Android 常见问题)
# 检查 SELinux 状态
getenforce# 如果是 Enforcing,可能需要临时关闭或设置 SELinux 策略
setenforce 0 # 临时关闭(仅用于测试)# 或者设置 SELinux 上下文
chcon u:object_r:binfmt_misc_exec:s0 /proc/sys/fs/binfmt_misc/register
检查 4:使用不同的写入方法
# 方法 1:使用 echo(标准方法)
echo ':qemu-x86_64:...' > /proc/sys/fs/binfmt_misc/register# 方法 2:使用 printf(避免 shell 转义问题)
printf ':qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/system/bin/qemu-x86_64-static:OPF' > /proc/sys/fs/binfmt_misc/register# 方法 3:使用 sh -c(绕过某些限制)
sh -c 'echo ":qemu-x86_64:..." > /proc/sys/fs/binfmt_misc/register'
检查 5:文件系统只读问题
# 检查 /proc 文件系统是否只读
mount | grep proc# 如果只读,可能需要重新挂载为可写(通常不需要,/proc 默认是可写的)
问题 5:是否需要写入固件?
答案:取决于你的使用场景
场景 A:临时测试(不需要写入固件)
如果只是临时测试,可以:
- 每次系统启动后手动配置
- 或者通过脚本在应用启动时配置(如果应用有 root 权限)
场景 B:生产环境(需要写入固件)
如果需要系统级支持,让所有用户都能使用,必须写入固件:
方法 1:修改 init.rc(推荐)
在系统镜像的 init.rc 或 init.${ro.hardware}.rc 中添加:
# 在 on early-init 或 on init 阶段添加
on early-init# 挂载 binfmt_miscmount binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc# 注册 x86_64 格式write /proc/sys/fs/binfmt_misc/register ":qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/system/bin/qemu-x86_64-static:OPF"
方法 2:创建 init 脚本
创建 /system/etc/init/qemu-binfmt.rc:
on early-initmount binfmt_misc binfmt_misc /proc/sys/fs/binfmt_miscwrite /proc/sys/fs/binfmt_misc/register ":qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/system/bin/qemu-x86_64-static:OPF"
方法 3:使用 shell 脚本(类似 Houdini)
创建 /system/bin/init.qemu-binfmt.sh,在系统启动脚本中调用:
#!/system/bin/sh
# 在 init.rc 中调用:exec /system/bin/init.qemu-binfmt.shbinfmt_misc_dir=/proc/sys/fs/binfmt_misc# 挂载 binfmt_misc
if [ ! -e $binfmt_misc_dir/register ]; thenmount -t binfmt_misc none $binfmt_misc_dir
fi# 注册 x86_64 格式
if [ -e $binfmt_misc_dir/register ]; thenecho ':qemu-x86_64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/system/bin/qemu-x86_64-static:OPF' > $binfmt_misc_dir/register
fi
固件修改步骤:
- 解包系统镜像(system.img)
- 添加 QEMU 二进制文件到
/system/bin/ - 修改
init.rc或创建 init 脚本 - 重新打包系统镜像
- 刷入设备
注意: 修改固件需要:
- 系统镜像的源代码或解包工具
- 重新签名(如果系统有验证)
- 可能需要解锁 bootloader
