标题: Linux Kernel核心中文手册 4-1 [打印本页] 作者: sam 时间: 2007-7-18 23:02 标题: Linux Kernel核心中文手册 4-1 每一次打开一个文件,就使用 files_struct 中的一个空闲的 file 指针指向这个新的 file 结构。 Linux 进程启动时有 3 个文件描述符已经打开。这就是标准输入、标准输出和标准错误,这都是从创建它们的父进程中继承过来的。对于文件的访问都是通过标准的系统调用,需要传递或返回文件描述符。这些描述符是进程的 fd 向量表中的索引,所以标准输入、标准输出和标准错误的文件描述符分别是 0 , 1 和 2 。对于文件的所有访问都是利用 file 数据结构中的文件操作例程和它的 VFS I 节点一起来实现的。
4.5 Virtual Memory (虚拟内存)
进程的虚拟内存包括多种来源的执行代码和数据。第一种是加载的程序映像,例如 ls 命令。这个命令,象所有的执行映像一样,由执行代码和数据组成。映像文件中包括将执行代码和相关的程序数据加载到进程地虚拟内存中所需要的所有信息。第二种,进程可以在处理过程中分配(虚拟)内存,比如用于存放它读入的文件的内容。新分配的虚拟内存需要连接到进程现存的虚拟内存中才能使用。第三中, Linux 进程使用通用代码组成的库,例如文件处理。每一个进程都包括库的一份拷贝没有意义, Linux 使用共享库,几个同时运行的进程可以共用。这些共享库里边的代码和数据必须连接到该进程的虚拟地址空间和其他共享该库的进程的虚拟地址空间。
在一个特定的时间,进程不会使用它的虚拟内存中包括的所有代码和数据。它可能包括旨在特定情况下使用的代码,比如初始化或者处理特定的事件。它可能只是用了它的共享库中一部分例程。如果把所有这些代码都加载到物理内存中而不使用只会是浪费。把这种浪费和系统中的进程数目相乘,系统的运行效率会很低。 Linux 改为使用 demand paging 技术,进程的虚拟内存只在进程试图使用的时候才调入物理内存中。所以, Linux 不把代码和数据直接加载到内存中,而修改进程的页表,把这些虚拟区域标志为存在但是不在内存中。当进程试图访问这些代码或者数据,系统硬件会产生一个 page fault ,把控制传递给 Linux 核心处理。因此,对于进程地址空间的每一个虚拟内存区域, Linux 需要直到它从哪里来和如何把它放到内存中,这样才可以处理这些 page fault 。
执行文件可以由许多格式甚至可以是一个脚本文件( script file )。脚本文件必须用合适的解释程序识别并运行。例如 /bin/sh 解释 shell script 。可执行的目标文件包括了执行代码和数据以及足够的其他信息,时的操作系统可以把它们加载到内存中并执行。 Linux 中最常用的目标文件类型是 ELF ,而理论上, Linux 灵活到足以处理几乎所有的目标文件格式。
好像文件系统一样, Linux 可以支持的二进制格式也是在核心连接的时候直接建立在核心的或者是可以作为模块加载的。核心保存了支持的二进制格式(见图 4.3 )的列表,当试图执行一个文件的时候,每一个二进制格式都被尝试,直到可以工作。通常, Linux 支持的二进制文件是 a.out 和 ELF 。可执行文件不需要完全读入内存,而使用叫做 demand loading 的技术。当进程使用执行映像的一部分的时候它才被调入内存,未被使用的映像可以从内存中废弃。
参见 fs/exec.c do_execve()
ELF
ELF ( Executable and Linkable Format 可执行可连接格式)目标文件,由 Unix 系统实验室设计,现在成为 Linux 最常用的格式。虽然和其他目标文件格式比如 ECOFF 和 a.out 相比,有性能上的轻微开支, ELF 感觉更灵活。 ELF 可执行文件包括可执行代码(有时叫做 text )和数据( data )。执行映像中的表描述了程序应该如何放到进程的虚拟内存中。静态连接的映像是用连接程序( ld )或者连接编辑器创建的,单一的映像中包括了运行该映像所需要的所有的代码和数据。这个映像也描述了该映像在内存中的布局和要执行的第一部分代码在映像中的地址。
脚本文件是需要解释器才能运行的可执行文件。 Linux 下有大量的解释器,例如 wish 、 perl 和命令解释程序比如 tcsh 。 Linux 使用标准的 Unix 约定,在脚本文件的第一行包括解释程序的名字。所以一个典型的脚本文件可能开头是:
#!/usr/bin/wish
脚本文件加载器试图找出文件所用的解释程序。它试图打开脚本文件第一行指定的可执行文件。如果可以打开,就得到一个指向该文件的 VFS I 节点的指针,然后执行它去解释脚本文件。脚本文件的名字成为了参数 0 (第一个参数),所有的其他参数都向上移动一位(原来的第一个参数成为了第二个参数等等)。加载解释程序和 Linux 加载其他可执行程序一样。 Linux 依次尝试各种二进制格式,直到可以工作。这意味着理论上你可以把几种解释程序和二进制格式堆积起来,让 Linux 的二进制格式处理程序更加灵活。