在C中,何时执行程序和共享库之间的动态链接:
将程序加载到内存中,但在执行程序的main()
之前,或
执行程序的main()
后,执行从库中第一次调用例程的时间?当执行第二个或第三个或......来自库的例程调用时,是否会再次发生动态链接?
我在想第一个,直到我读到以下引用,现在我不确定。
不确定操作系统是否重要,我使用的是Linux。
来自操作系统概念:
通过动态链接,每个图像中都包含一个存根 图书馆 - 例行参考。存根是一小段代码 指示如何找到适当的内存驻留库 例程或如果例程尚未加载库的方法 当下。
执行存根时,它会检查所需的例程是否已经在内存中。如果不是,程序加载 常规进入记忆。无论哪种方式,存根替换自己 例程的地址并执行例程。因此,下一次 达到特定代码段,库例程是 直接执行,不会产生动态链接的成本。在此之下 scheme,所有使用语言库的进程只执行一个 库代码的副本。
答案 0 :(得分:1)
我在想第一个,直到我读到以下引用,现在我不确定。
它很复杂(并且完全取决于你所谓的“动态链接”)。
Linux内核将a.out
加载到内存中。然后它会检查PT_INTERP
段(如果有的话)。
如果该段不存在,则二进制文件静态链接,内核将控制权转移到Elf{32,64}Ehdr.e_entry
(通常是_start
例程)。
如果PT_INTERP
段 存在,则内核将其加载到内存中,并将控制转移到它的 .e_entry
。在这里,动态链接开始。
动态加载程序重新定位,然后在a.out
s PT_DYNAMIC
段中查找有关其他必要内容的说明。
例如,它通常会找到一个或多个DT_NEEDED
条目 - a.out
直接链接的共享库。加载程序加载任何此类库,初始化它们,并解析它们之间的任何数据引用。
如果a.out
s PT_DYNAMIC
有一个DT_FLAGS
条目,如果该条目包含DF_BIND_NOW
标记,那么 function 引用{{1也将被解决。否则(并假设未在环境中设置a.out
),将执行惰性LD_BIND_NOW
解析(将函数解析为对任何给定函数的第一次调用的一部分)。详情here。
执行存根时,它会检查所需的例程是否已经在内存中。如果不是,程序会将例程加载到内存中。
我不知道你引用哪本书,但当前的UNIX操作系统没有这种方式。
答案 1 :(得分:1)
操作系统(和编译器,等。)当然很重要:语言本身对动态库没什么好说的(和very little一般关于链接)。即使我们知道正在发生动态链接,但严格一致的程序也无法观察到其翻译单元之间的时序效应(因为非本地初始化cannot have side effects)。
也就是说,Linux上的常见工具链在加载动态库时支持automatic initialization(用于实现C ++等)。可执行文件及它们所依赖的动态库(通常用-l
指定)是loaded and initialized recursively,以允许在每个模块中初始化(成功)使用其依赖项中的函数。 (在某些情况下,订单会有unfortunate choice。)当然,dlopen(3)
可以用来加载和初始化更多的库。