有关共享库的问题

时间:2014-04-05 05:24:45

标签: linux shared-libraries

我对共享库有一些疑问

  1. 当我运行二进制文件时,谁将加载共享库取决于共享 库(.so)?

  2. 加载共享库的位置?

  3. 如果共享库已经加载,我运行二进制文件取决于 加载的库,在这种情况下将加载共享库 或二进制文件将使用加载的库?

2 个答案:

答案 0 :(得分:4)

  

运行二进制文件时谁将加载共享库取决于共享库(.so)?

当您exec二进制文件时,Linux内核将读取您文件的elf标头。所有动态链接的ELF文件都在{ELF文件中的程序头/lib/ld-linux.so.2(解释器)中注册了.interp(运行时动态链接器)。当存在解释器时,Linux内核将加载解释器的ELF(通过根据其头部将其mmaping到内存中),并跳转到其入口点。

运行时动态链接器将读取动态链接的程序,找到所有需要的共享库并将它们加载到内存中(再次使用mmap和ELF头中的信息)。

  

加载共享库的地方?

在运行时库搜索路径($LD_LIBRARY_PATH/etc/ld.so.conf)中列出的所有目录中搜索共享库。

用于加载每个库的内存地址由ld-linux.so.2确定(可能由内核确定,例如随机化起始地址)。

库加载的实际代码是glibc,elf/rtld.c文件http://fxr.watson.org/fxr/source/elf/rtld.c?v=GLIBC27#L1731

 1731   /* Load all the libraries specified by DT_NEEDED entries. ....  */
 1735   _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);

然后,链接器将连接目标文件之间的符号引用(重定位过程,如果在延迟绑定处于活动状态时实际引用符号,有时会执行此操作)。

  

如果已加载共享库并且我运行二进制文件取决于加载的库,在这种情况下将加载共享库或二进制文件将使用加载的库?

您应该知道mmap如何处理文件。存储在硬盘驱动器(HDD或SSD)上的文件应该加载到内存中以便执行。链接器不会mmap整个库文件;只有具有库数据和代码的部分。此外,mmap系统调用是惰性的,它不会将所有请求的文件加载到内存中,但只记住相应的虚拟页面和文件偏移量。在第一次访问虚拟页面时,将发生pagefault(主要页面故障),并且将从HDD读取文件的一部分(Linux可能从磁盘加载更多页面;还有预取程序可以尽早将库读取到内存中在启动过程中。)

如果多个进程mmap是同一个文件,则将使用Copy-On-Write机制。这意味着:如果只读取内存页面,则会有一个物理页面。几个虚拟页面将映射到它;一切都被禁止"写"访问。对于页面上的每次写入访问,复制将完成(通过次要页面故障),原始物理页面如果被复制到新的物理页面;并且将对执行写访问的进程更改映射。从pagefault中断返回后,write指令将重新启动,写入自己的页面副本。

共享库的大多数可执行代码都没有写入,因此它在所有进程之间共享。数据段(.data,.bss,.tdata,.bss)将不会被共享,因为它们都有写入。重定位也会取消共享某些页面。

答案 1 :(得分:3)

您的问题1和2的答案是:它取决于您使用的操作系统。在大多数UNIX操作系统上,运行时加载程序(通常为ld.sold-linux.so)将加载共享库,无论何时它都可以这样做。

对于问题3,通常共享库在进程之间是共享,所以是的:新加载的可执行文件将重用已由其他一些加载的共享库处理。注意:只共享代码(和只读数据)段;每个进程都有自己的可写数据段副本。

  

寻找可信和/或官方来源的答案。

对于Linux,this guide详细说明了共享库加载的过程(可能包含的信息比你关心的更多)。

此外,this book在线提供early draft