程序链接
所谓链接,就是编译器找到程序中所引用的函数或全局变量所存在的位置。
一般来说,程序的链接分为静态链接和动态链接,静态链接就是把所有所引用到的函数或变量全部地编译到可执行文件中。
动态链接则不会把函数编译到可执行文件中,而是在程序运行时动态地载入函数库,也就是运行链接。所以,对于动态链接来说,必然需要一个动态链接库。
动态链接库的好处在于,一旦动态库中的函数发生变化,对于可执行程序来说是透明的,可执行程序无需重新编译。这对于程序的发布、维护、更新起到了积极的作用。
对于静态链接的程序来说,函数库中一个小小的改动需要整个程序的重新编译、发布,对于程序的维护产生了比较大的工作量。
程序解释器
可执行文件可以包含 PT_INTERP(ELF目标文件中段类型的一种)程序头部元素。在 exec() 期间,系统从 PT_INTERP 段中检索路径名,并从解释器文件的段创建初始的进程映像。
也就是说,系统并不使用原来可执行文件的段映像,而是为解释器构造一个内存映像。接下来是解释器从系统接收控制,为应用程序提供执行环境。
解释器可以有两种方式接受控制:
- 接受一个文件描述符,读取可执行文件并将其映射到内存中
- 根据可执行文件的格式,系统可能把可执行文件加载到内存中,而不是为解释器提 供一个已经打开的文件描述符。
解释器可以是一个可执行文件,也可以是一个共享目标文件。
共享目标文件被加载到内存中时,其地址可能在各个进程中呈现不同的取值。系统在 mmap 以及相关服务所使用的动态段区域创建共享目标文件的段。因此共享目标解释器通常不会与原来的可执行文件的原始段地址发生冲突。可执行文件被加载到内存中固定地址,系统使用来自其程序头部表的虚拟地址创建各个段。因此可执行文件解释器的虚拟地址可能会与原来的可执行文件的虚拟地址发生冲突。解释器要负责解决这种冲突。
动态加载程序
在构造使用动态链接技术的可执行文件时,链接编辑器向可执行文件中添加一个类型为 PT_INTERP 的程序头部元素,告诉系统要把动态链接器激活,作为程序解释器。系统所提供的动态链接器的位置是和处理器相关的。 Exec() 和动态链接器合作,为程序创建进程映像,其中包括以下动作:
(1). 将可执行文件的内存段添加到进程映像中;
(2). 把共享目标内存段添加到进程映像中;
(3). 为可执行文件和它的共享目标执行重定位操作;
(4). 关闭用来读入可执行文件的文件描述符,如果动态链接程序收到过这样的 文件描述符的话;
(5). 将控制转交给程序,使得程序好像从 exec 直接得到控制。
链接编辑器也会构造很多数据来协助动态链接器处理可执行文件和共享目标文件。这些数据包含在可加载段中,在执行过程中可用。