当前位置: 首页 > news >正文

交叉编译与 QEMU 启动最小 Linux:一个“32 位内核跑 64 位程序“的启动陷阱(srvC)

交叉编译与 QEMU 启动最小 Linux:一个"32 位内核跑 64 位程序"的启动陷阱(srvC)

本篇基于 srvC(phase5)真实实操,是整个系列里最值得收藏的一篇。我们交叉编译 BusyBox 与内核、制作 initramfs 根文件系统、用 QEMU 把 ARM 和 x86 的最小 Linux 都跑了起来;但 x86 启动一路报error -2error -8,排查过程把"initramfs 启动失败"的几乎所有经典坑都踩了一遍。


1. 目标与链路

一条完整的"在 QEMU 里跑起 Linux"链路是:

BusyBox(根文件系统_app) + Linux内核 + 根文件系统(initramfs) + QEMU(机器模拟)
  • ARM 侧:交叉编译静态 ARM BusyBox → 编译multi_v7_defconfig内核 →vexpress-a15板型 QEMU 启动
  • x86 侧:用宿主机静态 x86_64 BusyBox → 编译tinyconfig内核 →qemu-system-x86_64启动

2. ARM 链路:一次成功

ARM BusyBox 交叉编译(关掉会导致 glibc 2.39 不兼容的CONFIG_TC,静态链接):

sed-i's/^CONFIG_TC=y/# CONFIG_TC is not set/'.configmakeCROSS_COMPILE=arm-linux-gnueabihf--j8# 产出约 1.5M 的静态 ARM busybox,可在 qemu-arm-static 下直接运行

内核与设备树:

makeARCH=arm multi_v7_defconfigmakeARCH=armCROSS_COMPILE=arm-linux-gnueabihf--j8zImage# 同时得到 arch/arm/boot/dts/arm/vexpress-v2p-ca15_a7.dtb

QEMU 启动vexpress-a15

qemu-system-arm-Mvexpress-a15-cpucortex-a15-m512M\-kernellinux-6.6.151/arch/arm/boot/zImage\-dtbvexpress-v2p-ca15_a7.dtb\-initrdrootfs-arm.cpio.gz-append'console=ttyAMA0 rdinit=/init'-nographic

启动后/init跑演示脚本,打印进程列表并干净关机:

71 0 0:00 ps 演示命令执行完毕, 系统即将关机... [ 2.522735] reboot: Power down

ARM 侧multi_v7_defconfig默认开了BINFMT_ELF/BINFMT_SCRIPT,所以脚本化的/init直接就能跑。

3. x86 链路:第一道坎error -2

x86 侧用宿主机的静态 busybox 做根文件系统,qemu-system-x86_64一启动却卡在 init:

Run /init as init process Failed to execute /init (error -2) Run /sbin/init as init process Starting init: /sbin/init exists but couldn't execute it (error -40) Run /etc/init as init process Run /bin/init as init process Run /bin/sh as init process Kernel panic - not syncing: No working init found. Try passing init= option to kernel.

error -2ENOENT(文件/解释器找不到)。第一直觉是initramfs 里的软链接指错了路径。BusyBox 的busybox --install -s会在bin/sbin/下生成大量指向 busybox 的软链接,如果目标写成绝对宿主机路径(如/root/lab/phase5/rootfs-x86/bin/busybox),在内存根文件系统里当然找不到。

抽取 cpio 检查真实目标,确认确实不对,修正为相对目标

# bin/* 指向同目录兄弟 busybox;sbin/* 指向 ../bin/busyboxforlinbin/*;do[-L"$l"]&&ln-sfbusybox"$l";doneforlinsbin/*;do[-L"$l"]&&ln-sf../bin/busybox"$l";done

修正后bin/sh -> busyboxsbin/init -> ../bin/busybox都在,重打 cpio 再启动——还是失败,只是报错从-2变成了-8

4. 第二道坎error -8:内核没开二进制加载器

-8ENOEXEC(执行格式错误)。抽内核配置一看,问题在tinyconfig默认把二进制加载器都关了:

$grep-E'BINFMT_ELF|BINFMT_SCRIPT'linux-src/.config CONFIG_BINFMT_ELF=# CONFIG_BINFMT_ELF is not setCONFIG_BINFMT_SCRIPT=# CONFIG_BINFMT_SCRIPT is not set

内核根本不认识 ELF 和#!脚本,自然跑不了 busybox,也跑不了/init脚本。打开它们并重建:

./scripts/config--enableCONFIG_BINFMT_ELF ./scripts/config--enableCONFIG_BINFMT_SCRIPTmakeolddefconfig&&make-j$(nproc)bzImage

再启动,报错仍-8。说明还有更深的根因。

5. 终极根因:32 位内核 vs 64 位 BusyBox

继续抽配置,决定性的一条出现了:

$grep-E'CONFIG_X86_32|CONFIG_64BIT'linux-src/.configCONFIG_X86_32=y# ← 内核被编成了 32 位!

而根文件系统里的 busybox 是64 位 ELF(x86-64)。一个 32 位内核去exec一个 64 位程序,正是ENOEXEC——它压根不认这个格式。宿主机的chroot测试能跑(主机是 64 位内核),更反证了这一点:

$chroot/tmp/inspect_x86 /bin/sh-c'echo CHROOT_OK'CHROOT_OK

修复:把内核翻回 64 位,重建 bzImage:

makeclean ./scripts/config--disableCONFIG_X86_32 ./scripts/config--enableCONFIG_64BIT# 同时保留 ELF/SCRIPT/INITRD/DEVTMPFS_MOUNTmakeolddefconfig&&make-j$(nproc)bzImage

6. 终见曙光

qemu-system-x86_64-m512M-kernellinux-src/arch/x86/boot/bzImage\-initrdrootfs-x86.cpio.gz-append'console=ttyS0 rdinit=/init'-nographic
--- 当前进程 --- PID USER COMMAND 1 0 {init} /bin/sh /init ← /init 脚本作为 1 号进程运行 25 0 {ps} /bin/sh /init 演示命令执行完毕, 系统即将关机... reboot: System halted

x86 的最小 Linux 终于干净启动并关机。

7. 排错决策树(收藏)

initramfs 启动失败,按错误码顺藤摸瓜:

错误码含义优先排查
error -2(ENOENT)文件/解释器找不到/init软链接目标、#!解释器在 initramfs 内是否存在
error -8(ENOEXEC)执行格式错误内核是否开CONFIG_BINFMT_ELF/BINFMT_SCRIPT内核位数与根文件系统里 ELF 的位数是否匹配(32-bit 内核 ≠ 64-bit 程序)

一句话:先查软链接,再查BINFMT_*,最后一定核对内核架构和根文件系统里程序的架构是否一致。

8. 小结

  • ARM 用multi_v7_defconfig默认配置即开箱可用;x86 用tinyconfig需手动补BINFMT_ELF/SCRIPT并确认是 64 位内核;
  • initramfs 的软链接必须是相对路径、且指向 initramfs 内部存在的文件;
  • “32 位内核跑 64 位 busybox” 这种架构错配,表现就是顽固的ENOEXEC,靠chroot对比即可快速定位。

下一篇进 srvD:自己写内核模块、字符设备与 platform 总线驱动。

http://www.jsqmd.com/news/1400455/

相关文章:

  • 无障碍设计在Welcome UI中的实现:符合WCAG标准的React组件
  • 别再熬夜导表格了:用Redash为GitHub仓库搭建自动数据看板
  • 2026 佛山高端家具工厂深度优选|DICCI 的驰家居,龙江自有产业园双品牌全案高定源头厂 - siouxx
  • 2026加盟天猫养车管得严吗?管控边界与门店自主空间拆解 - Chencen
  • 微信去水印小程序详细搭建教程(附源码)
  • 如何让 Chrome 告别卡顿:Marvellous Suspender 标签页挂起扩展完整使用指南
  • 微信聊天记录会消失吗?WeChatMsg 备份工具永久保存完整教程
  • 2026年AI生成式引擎优化深度解析与选型指南 - 老林说收银
  • 深入text-to-motion代码库:核心模块与关键函数详解
  • 河南南阳市文武学校哪家靠谱?2026 招生汇总,省内知名文武学校核心简章要点 - Luckyone王
  • 如何用 trash-cli 告别误删噩梦:5 个提升数据安全的实战技巧
  • RAGMeUp开发者指南:自定义Chunkers与Retrievers的完整教程
  • Bootstrap 4 Login Page Template部署指南:从下载到上线的完整流程
  • gemma4-browser-extension:革命性本地AI浏览器助手,无需服务器的隐私保护方案
  • CDH集群6.3.2 + CM6.3.1离线安装部署实操保姆级详细教程
  • Combine:一站式威胁情报收集工具,快速获取公开源威胁指标
  • 渭南市各区县现浇楼梯施工改造 资质核查与工程服务指南 - 名字不是很重要
  • 河南济源少林文武学校靠谱吗?2026 招生简章,全托班费用、核心要点汇总 - Luckyone王
  • BT 下载提速 3 步实操:用 trackerslist 选对 Tracker 服务器,告别龟速
  • 如何在5分钟内上手steampy:从安装到发送第一个交易报价
  • Markdown7开发者指南:扩展语法与自定义解析规则
  • 卫浴源头工厂太空铝花洒选购指南:如何选到耐用环保花洒 - 全域品牌推荐
  • atc-react与AMITT框架结合:应对虚假信息攻击的终极事件响应策略
  • Audio8-ASR-0.1B核心功能全解析:从多语言支持到1.1GB低内存占用
  • Shovel命令行详解:掌握--verbose调试与--dry-run预览的实用技巧
  • 免安装微信客户端,一个插件就能搞定:wechat-need-web 完整指南
  • 河南平顶山家长收藏!河南有名文武学校有哪些?2026 招生,一文看懂怎么选武校 - Luckyone王
  • 2026 河南鹤壁文武学校招生指南|省内知名院校大盘点,不同地区武校怎么选 - Luckyone王
  • 从入门到精通:ng-token-auth开发实战与最佳实践
  • 深入理解tumblr.js架构:从源码解析到自定义请求实现