我对共享库有一些疑问
当我运行二进制文件时,谁将加载共享库取决于共享 库(.so)?
加载共享库的位置?
如果共享库已经加载,我运行二进制文件取决于 加载的库,在这种情况下将加载共享库 或二进制文件将使用加载的库?
答案 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.so
或ld-linux.so
)将加载共享库,无论何时它都可以这样做。
对于问题3,通常共享库在进程之间是共享,所以是的:新加载的可执行文件将重用已由其他一些加载的共享库处理。注意:只共享代码(和只读数据)段;每个进程都有自己的可写数据段副本。
寻找可信和/或官方来源的答案。
对于Linux,this guide详细说明了共享库加载的过程(可能包含的信息比你关心的更多)。
此外,this book在线提供early draft。