按段建立程序映像
ELF程序头描述哪些文件区域成为可加载段,以及对应的虚拟地址、权限和大小。内存范围比文件数据更大时,额外部分按规则填零;加载不是把文件所有字节不加区分地复制到同样编号的内存地址。
Linux的execve在成功时替换调用进程的程序映像,而不自动创建另一个进程。进程如何产生与映像如何装入可以分别实现;这一区别也说明,看到程序启动并不能仅凭加载器就推断进程创建方式。
内核加载与动态链接器分工
动态链接的ELF可在PT_INTERP中指定解释器。系统将控制交给相应组件,动态链接器再装入所需共享对象、处理适用重定位并准备程序执行;不能把所有工作都归给编译器,也不能认为每次函数调用都会重走完整加载流程。
具体实现可推迟部分函数绑定,直到首次使用;也可要求启动时完成。Linux动态链接器的LD_BIND_NOW就是控制立即绑定的一种方式。这些选择影响何时解析,并不改变程序仍须满足相应接口和地址规则的要求。
依赖路径与初始化有自己的规则
Linux动态链接器区分含斜杠的依赖路径与需要搜索的名字,并综合运行路径、环境、缓存和系统目录等规则。RUNPATH通常只适用于该对象的直接依赖,不能假定自动覆盖所有后代;$ORIGIN展开为有关程序或共享对象所在目录,也不是当前工作目录。
共享对象映射和修正后,还可能执行初始化函数;ELF规则对依赖先后、初始化数组等作出约定,循环依赖的先后则未必确定。依赖文件找到、映像装入、初始化结束与应用逻辑成功,仍是应分别确认的状态。