linux进程间通信机制6:执行程序_茅坑_百度空间
和 UNIX 类似,Linux 中的程序和命令通常由命令解释器执行,这一命令解释器称为 shell。用户输入命令之后,shell 会在搜索路径(shell 变量PATH中包含搜索路径)指定的目录中搜索和输入命令匹配的映象名称。如果发现匹配的映象,shell 负责装载并执行该命令。shell 首先利用 fork 系统调用建立子进程,然后用找到的可执行映象文件覆盖子进程正在执行的 shell 二进制映象。
可执行文件可以是具有不同格式的二进制文件,也可以是一个文本的脚本文件。可执行映象文件中包含了可执行代码及数据,同时也包含操作系统用来将映象正确装入内存并执行的信息。Linux 使用的最常见的可执行文件格式是 ELF 和 a.out,但理论上讲,Linux 有足够的灵活性可以装入任何格式的可执行文件。
11.4.1 ELF(Executable Link Format)
ELF 是“可执行可连接格式”的英文缩写,该格式由 UNIX 系统实验室制定。它是 Linux 中最经常使用的格式,和其他格式(例如 a.out 或 ECOFF 格式)比较起来,ELF 在装入内存时多一些系统开支,但是更为灵活。ELF 可执行文件包含了可执行代码和数据,通常也称为正文和数据。这种文件中包含一些表,根据这些表中的信息,内核可组织进程的虚拟内存。另外,文件中还包含有对内存布局的定义以及起始执行的指令位置。
我们分析如下简单程序在利用编译器编译并连接之后的 ELF 文件格式:
#include <stdio.h>

main ()
{
   printf(“Hello world!\n”);
}
如图 11-5 所示,是上述源代码在编译连接后的 ELF 可执行文件的格式。从图 11-5 可以看出,ELF 可执行映象文件的开头是三个字符 ‘E’、‘L’ 和 ‘F’,作为这类文件的标识符。e_entry 定义了程序装入之后起始执行指令的虚拟地址。这个简单的 ELF 映象利用两个“物理头”结构分别定义代码和数据,e_phnum 是该文件中所包含的物理头信息个数,本例为 2。e_phyoff 是{dy}个物理头结构在文件中的偏移量,而e_phentsize 则是物理头结构的大小,这两个偏移量均从文件头开始算起。根据上述两个信息,内核可正确读取两个物理头结构中的信息。
物理头结构的 p_flags 字段定义了对应代码或数据的访问属性。图中{dy}个 p_flags 字段的值为 FP_X 和 FP_R,表明该结构定义的是程序的代码;类似地,第二个物理头定义程序数据,并且是可读可写的。p_offset 定义对应的代码或数据在物理头之后的偏移量。p_vaddr 定义代码或数据的起始虚拟地址。p_filesz 和 p_memsz 分别定义代码或数据在文件中的大小以及在内存中的大小。对我们的简单例子,程序代码开始于两个物理头之后,而程序数据则开始于物理头之后的第 0x68533 字节处,显然,程序数据紧跟在程序代码之后。程序的代码大小为 0x68532,显得比较大,这是因为连接程序将 C 函数 printf 的代码连接到了 ELF 文件的原因。程序代码的文件大小和内存大小是一样的,而程序数据的文件大小和内存大小不一样,这是因为内存数据中,起始的 2200 字节是预先初始化的数据,初始化值来自 ELF 映象,而其后的 2048 字节则由执行代码初始化。


图 11-5 一个简单的 ELF 可执行文件的布局


如上一章中所描述的,Linux 利用需求分页技术装入程序映象。当 shell 进程利用 fork 系统调用建立了子进程之后,子进程会调用 exec 系统调用(实际有多种 exec 调用),exec 系统调用将利用 ELF 二进制格式装载器装载 ELF 映象,当装载器检验映象是有效的 ELF 文件之后,就会将当前进程(实际就是父进程或旧进程)的可执行映象从虚拟内存中xx,同时xx任何信号处理程序并关闭所有打开的文件(把相应 file 结构中的 f_count 引用计数减 1,如果这一计数为 0,内核负责释放这一文件对象),然后重置进程页表。完成上述过程之后,只需根据 ELF 文件中的信息将映象代码和数据的起始和终止地址分配并设置相应的虚拟地址区域,修改进程页表。这时,当前进程就可以开始执行对应的 ELF 映象中的指令了。
和静态连接库不同,动态连接库可在运行时连接到进程虚拟地址中。对于使用同一动态连接库的多个进程,只需在内存中保留一份共享库信息即可,这样就节省了内存空间。当共享库需要在运行时连接到进程虚拟地址时,Linux 的动态连接器利用 ELF 共享库中的符号表完成连接工作,符号表中定义了 ELF 映象引用的全部动态库例程。Linux 的动态连接器一般包含在 /lib 目录中,通常为 ld.so.1、llibc.so.1 和ld-linux.so.1。
11.4.2 脚本文件
脚本文件实际是一些可执行的命令,这些命令一般由指定的解释器解释并执行。Linux 中常见的解释器有 wish、perl 以及命令 shell,如 bash 等。
一般来说,脚本文件的{dy}行用来指定脚本的解释程序,例如:
#!/usr/bin/wish
这行内容指定由 wish 作为该脚本的命令解释器。脚本的二进制装载器利用这一信息搜索解释器,如果能够找到指定的解释器,该装载器就和上述执行 ELF 程序的装载过程一样装载并执行解释器。脚本文件名成为传递给解释器的{dy}个命令参数,而最初的{dy}个参数则成为现在的第二个参数,依此类推。为解释器传递了正确的命令参数后,就可由脚本解释器执行脚本。



郑重声明:资讯 【linux进程间通信机制6:执行程序_茅坑_百度空间】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——