接着上一篇博客。前面的工作都是在内核完成的,接下来会回到用户空间。
第一步,解释器(也可以叫动态链接器)首先检查可执行程序所依赖的共享库,并在需要的时候对其进行加载。
ELF 文件有一个特别的节区: .dynamic,它存放了和动态链接相关的很多信息,例如动态链接器通过它找到该文件使用的动态链接库。不过,该信息并未包含动态链接库的绝对路径,但解释器通过 LD_LIBRARY_PATH 参数可以找到(它类似 Shell 解释器中用于查找可执行文件的 PATH 环境变量,也是通过冒号分开指定了各个存放库函数的路径)该变量实际上也可以通过/etc/ld.so.conf 文件来指定,一行对应一个路径名。为了提高查找和加载动态链接库的效率,系统启动后会通过 ldconfig 工具创建一个库的缓存 /etc/ld.so.cache 。如果用户通过 /etc/ld.so.conf 加入了新的库搜索路径或者是把新库加到某个原有的库目录下,最好是执行一下 ldconfig 以便刷新缓存。
找到动态链接库后,就可以将其加载到内存中。
第二步,解释器对程序的外部引用进行重定位,并告诉程序其引用的外部变量/函数的地址,此地址位于共享库被加载在内存的区间内。动态链接还有一个延迟定位的特性,即只有在“真正”需要引用符号时才重定位,这对提高程序运行效率有极大帮助。(如果设置了 LD_BIND_NOW 环境变量,这个动作就会直接进行)
下面具体说明符号重定位的过程。
首先了解几个概念。符号,也就是可执行程序代码段中的变量名、函数名等。