BusyBox 中文文档 下载 App

多调用二进制原理 一个文件如何装下数百个命令

什么是多调用二进制

多调用二进制(Multi-call Binary)是一个可执行文件,运行时可以表现为完全不同的程序——不是通过命令行参数切换,而是看它的"名字"。

具体来说:操作系统在执行程序时,argv[0] 会被设为调用它的那个路径。如果我创建一个符号链接 ln -s busybox ls,然后执行 ./ls,那么这个符号链接指向的 busybox 二进制会被执行,argv[0] 就是 "./ls"。BusyBox 拿到这个名字,查表发现 "ls" 对应它内部的 ls 实现,于是切换到 ls 模式。

# 方式一:通过符号链接(最常见)
ln -s busybox /bin/ls
ln -s busybox /bin/cat
ln -s busybox /bin/sh
# 然后直接用
ls -la /tmp
cat /etc/passwd

# 方式二:直接指定子命令(不需要符号链接)
busybox ls -la /tmp
busybox cat /etc/passwd
busybox sh    # 启动 ash shell

两种运行模式的区别

模式内存占用适合场景
符号链接模式每个命令一个 inode,但代码段共享嵌入式系统根文件系统
直接调用模式只有一个 busybox 二进制容器、临时救援、不想搞一堆符号链接

符号链接模式在嵌入式设备上更常见,因为根文件系统会有几十个常用命令的符号链接指向同一个 busybox。这种模式下,每个命令的"身份"由文件路径决定,busybox 启动时先确认自己"叫什么"再决定行为。

直接调用模式适合临时场景——比如在一台没有 shell 的极简系统上,你只需要上传一个 busybox 二进制,然后 busybox sh 就能拿到命令行。

实现细节

BusyBox 内部有一张 Applet 表,每个条目包含:

启动流程大致是:

  1. 读 argv[0],提取最后一个路径段作为命令名
  2. 在 Applet 表里查找匹配项
  3. 找到就执行对应函数,找不到就打印帮助

如果 argv[0] 是 "busybox" 本身(直接调用模式),则读 argv[1] 作为命令名;如果 argv 长度只有 1,就打印所有可用命令列表。

与独立程序的对比

传统 Unix 每个工具一个二进制,/bin 目录下有上百个独立的可执行文件。BusyBox 把它们合并后:

在现代嵌入式场景里,这个取舍几乎总是值得的——尤其是 Flash 存储容量紧张时,省出的空间可以留给应用数据、日志缓冲区或者更多功能。