一、 动态库的加载过程
1. 编译和链接:
- 链接器将目标文件和所需动态库链接为一个可执行文件,连接器只会在可执行文件中添加对动态库中函数的引用,而不会将动态库的代码和数据直接包含在可执行文件中
2. 可执行文件启动
- 用户运行可执行文件,系统将它加载到内存中,并设置各种运行时环境
- 调用main之前,系统会调用动态链接器
3. 动态链接器工作
- 检查可执行文件依赖关系,确认需要加载哪些库
- 读取动态库文件,将动态库中的代码和数据映射到程序的虚拟地址空间,通常使用mmap映射
- 解析可执行文件中对动态库中函数的引用,将这些引用替换为实际在内存中的地址
4. 程序执行:
- 链接器完成了上述动作后,程序就可以开始执行了
- 程序现在可以直接调用动态库中的函数,因为链接器已经解析了所有对库中函数的引用,并替换了相应的地址
二、 动态链接器如何确认需要加载那些库
1. 读取可执行文件信息:
- 动态链接器首先读取可执行文件头部信息,特别是那些与共享库依赖关系相关的信息,这些信息通常是在编译和链接的阶段由链接器添加到可执行文件中的。
2. 解析依赖关系
链接器解析可执行文件中的依赖信息,识别出程序需要调用的函数和变量是否位于动态库中,这通常涉及到检查可执行文件的重定位表和符号表
3. 搜索动态库
一旦确定了需要的动态库,链接器会在系统路径中搜索这些库,一般的搜索顺序
- 通过编译选项执行的目录如: -L、-rpath、-rpath-link等指定的搜索目录,这些选项告诉链接器在哪些目录中查找所需要的共享库
- 环境变量指定的目录,如LD_LIBRARY_PATH,这些环境变量可以包含一个或多个目录路径,链接器根据顺序搜索
- 通过/etc/ld.so.config文件中指定的路径
- /lib
- /usr/lib
4. 加载动态库
找到动态库会,链接器会加载这些库到程序的虚拟地址空间中,通常是mmap完成,会在内存中映射文件的代码和数据段
5. 解析符号
加载完后,链接器会解析可执行文件中对动态库函数的引用,它查找动态库中的符号表,将程序中的符号替换为库中的实际地址,这个过程确保了程序在调用动态库中函数时能够找到正确的地址