如果您对Linux兼容模式是如何工作的感到好奇,这节正是您所需要的。
下面的绝大部分内容是由 Terry Lambert<[email protected]>
(Message ID:
<[email protected]>)发表在邮件列表FreeBSD
闲聊邮件列表上的内容组成的。
FreeBSD有一个“可执行类加载器”。它主要是嵌入了execve(2)系统调用。
碰巧的是FreeBSD有一个引导器(loader)的列表,而不是一个简单的返回一个 符号 #!的引导器!
从历史上来讲,只有UNIX®平台的引导器会检查魔术(magic)数 (通常是文件的前4个或8个字节)是否是二进制的, 如果是,就调用二进制引导程序。
如果它不是二进制类型的execve(2)调用就会返回一个错误,shell就试图用shell命令执行它。
缺省是使用“当前设定的shell”。
随后,进行了一些hack, sh(1)开始检查前两个字符,如果它们是:\n, 那它就调用csh(1)(我们相信是SCO最先做这个hack的)。
FreeBSD现在所做的是用一个普通的#!引导器仔细检查引导器的列表, 然后由解释程序一个接一个地解释,返回给/bin/sh。
为了支持Linux ABI,FreeBSD就把魔术数看作为一个二进制ELF程序。( 这样一来,它就使得在FreeBSD, Solaris™,Linux和其他任何操作系统之间只要使用ELF格式就都可以顺利运行)。
ELF引导器会寻找一个专门的标记, 它是在ELF映像中的一个注释部分,但在SVR4/Solaris的ELF中没有。
为了执行Linux程序,它们必须被打上Linux类型的标记; 使用brandelf(1):
# brandelf -t Linux file
做完之后,ELF引导器就会看到文件上的Linux的标记。
当ELF引导器看到Linux的标记, 引导器就会在proc结构中替换一个指示器。 所有的系统调用就会通过这个指示器来索引(在一个传统的 UNIX系统中, 这就是sysent[]结构队列,包含系统调用)。 此外,为了解决由于信号杂乱所造成的陷阱向量的问题,会造成线程的剧增, 需要切断其他(或较小的)由Linux内核模块产生的修正。
Linux系统调用向量包含一个sysent[]记录的列表, 它的地址位于内核模块之中。
当一个系统调用被Linux程序调用时,有缺陷的代码会把系统调用功能的指示器从proc结构中解除, 然后获得Linux,而不是FreeBSD,系统调用入口点。
另外,Linux模式动态地reroots查找;这和启动文件系统的union
选项是等效的(即时不是unionfs文件系统)。 首先会试图在/compat/linux/original-path
目录查找文件,如果失败了,就会在/original-path
目录下查找。这使得需要其它程序的程序可以运行(例如,Linux工具链都可以在Linux
ABI的支持下工作)。
也就是说Linux程序可以加载和执行FreeBSD程序,如果当前没有相应的Linux程序, 那您可以在/compat/linux目录树中放置一个uname(1),来确保Linux程序不提示它们不能运行在Linux上。
在FreeBSD内核中有一个Linux内核;由内核提供的能够提供所有服务的各种潜在功能 在FreeBSD系统调用表记录和Linux系统调用表记录之间是一样的: 文件系统操作,虚拟内存操作,信号发送,System V IPC,...等等。 唯一的不同是FreeBSD会得到FreeBSD的胶合功能, 而Linux程序会得到Linux的胶合功能 (大部分老的操作系统只有它们自己的胶合函数, 函数地址在静态全局变量sysent[]结构数据里面, 而不是动态的初始化到进程的proc结构)。
哪一个是FreeBSD自己的ABI呢?这无关紧要。基本上, 唯一的不同是FreeBSD的胶合功能是被静态连接到内核, 而Linux的胶合功能可能是被静态连接到内核, 也可能它们通过一个内核模块来访问。
有一个真正的模拟器吗?没有,它只不过是一个ABI执行机制,不是一个模拟器。
为什么有时它被叫做“Linux模拟器”? 只是为了更容易地卖出FreeBSD罢了! 实际上,历史上从来没有描述这样一种执行机制的名字,FreeBSD并不是真正地运行Linux程序,如果您不编译进代码, 或加载一个模块。 就需要有一个名字来描述这样一种加载功能--因此就想出了“Linux模拟器”这样一个名字。
本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<[email protected]>.
关于本文档的问题请发信联系 <[email protected]>.