此章节将讲述是 Linux® 二进制兼容如何工作的,
内容基于 Terry Lambert <[email protected]>
(Message ID:
<[email protected]>
)
发表在 FreeBSD 闲聊邮件列表 的邮件。
FreeBSD 有一个叫 “execution class loader” 的抽象层。 它被嵌入进了 execve(2) 系统调用。
历史上 UNIX® 加载器会依靠查看魔数 (通常是文件的开头 4 至 8 个字节)来确认是否是系统已知的的二进制程序, 如果是的话, 就会调用二进制程序加载器。
如果它不是二进制类型的程序, execve(2) 调用会返回一个错误, shell 则会把它当作 shell 命令执行。 “不论当前是哪一种 shell” 都会默认做出此种假设。
随后, sh(1) 会检查开头的两个字符,
如果它们是 :\n
, 那么就调用 csh(1)。
FreeBSD 有一份加载器列表而不是一个单一的加载器, 并能回退到
#!
加载器来运行 shell 解释器或者 shell 脚本。
为了支持 Linux® ABI, FreeBSD 看到了二进制 ELF 程序的魔数。 ELF 加载器会查找一个专用的 标记, 那是在 ELF 镜像中的一个注释部分, 此区域在 SVR4/Solaris™ ELF 二进制中并不存在。
要运行 Linux® 二进制程序,
必须先使用 brandelf(1) 命令 标记 为
Linux
类型:
#
brandelf -t Linux file
当 ELF 加载器看到了 Linux
标记,便会替换 proc
结构中的一个指针。
所有的系统调用都通过此指针来索引。 除此以外,
进程被标记以便对 signal trampoline 代码的陷阱向量做特殊处理,
还有一些其他由 Linux® 内核模块来处理的(细微)修补。
Linux® 系统调用向量包含一个 sysent[]
记录的列表, 它的地址位于内核模块之中。
当一个系统调用被 Linux® 二进制程序调用时,
陷阱代码会把系统调用函数指针从 proc
解引用至 Linux® 而不是 FreeBSD 的系统调用入口。
Linux® 模式会动态地 reroots 查找。
这与 union
文件系统选项是等效的。
首先会试图在 /compat/linux/
目录查找文件。 如果失败了, 就会在 original-path
/
目录下查找。 这使得需要其它程序的程序得以运行。 例如,Linux®
工具链都可以在 Linux® ABI 的支持下运行。
也就是说 Linux® 二进制程序可以加载并执行 FreeBSD 二进制程序,
如果当前没有相应的 Linux® 二进制程序,
可以在 original-path
/compat/linux
目录树中放置一个
uname(1) 命令, 使 Linux® 程序不易察觉它们并没有运行在 Linux®
系统上。
事实上, 在 FreeBSD 内核中有一个 Linux® 内核。 所有由内核提供的服务的各种底层功能在 FreeBSD 系统调用表的记录和 Linux® 系统调用表的记录是一样的: 文件系统操作, 虚拟内存操作, 信号发送, 和 System V IPC。 唯一的不同是 FreeBSD 会得到 FreeBSD 的 glue 功能, 而 Linux® 程序会得到 Linux® 的 glue 功能。 FreeBSD 的 glue 功能是静态链接入内核的, 而 Linux® 的 glue 功能可以静态链接, 或者通过内核模块访问。
严格说来其实并没有真正的模拟, 这是一种 ABI 的实现。 有时这被称为 “Linux® 模拟” 是因为在实现的时候还没有其他适合的词用来描述。 要说 FreeBSD 运行 Linux® 二进制程序并不确切, 因为当时代码并还没有被编译进去。
本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读
文档,如不能解决再联系
<[email protected]>.
关于本文档的问题请发信联系
<[email protected]>.