我对C语言中的动态链接库有疑问。
Q1。 customer code
我的教科书使用图片说明DLL的工作原理,
并且似乎复制了libvector.so
和libc.so
的一些重定位和符号表信息(箭头附加在其侧面),但是只要汇编器遇到对最终位置未知的对象的引用,它生成一个重定位条目,告诉链接器将目标文件合并到可执行文件时如何修改引用。对于libc.so,一切都是已知的(具有所有定义),因此libc.so不应有任何重定位条目,不是吗
Q2。我的教科书说:
“内存中共享库.text部分的单个副本可以由不同的运行进程共享”,
假设我有一个使用printf
的程序。 .text
的{{1}}部分是永久保留在RAM中还是在第一个程序完成时从RAM中驱逐,而在第二个进程再次使用printf
时又被加载到RAM中?
如果是后者,那么printf
的{{1}}段被逐出并多次加载到RAM中不是很低效,因为我们有多个进程可能在后台运行? / p>
答案 0 :(得分:4)
问题1:您提供的图表对我来说似乎是正确的。 main2
正在构建; libvector.so
和libc.so
的重定位和符号表信息将被复制到其中,以便最终的可执行文件可以使用它们。从main2
的角度来看,正在添加libc
和libvector
中的函数,常量等,因此,我同意您的教科书的观点,{{1}的重定位和符号表信息}和libvector.so
正在复制。
第二季度:您仅提出两个极端:“永远呆在RAM中”或“在第一个程序完成时从RAM中退出”。几乎可以肯定,只要一些最近运行的进程使用了可共享部分,它们就将保留在RAM中。操作系统将使用的一种典型策略是LRU算法,以从RAM中驱逐“未使用”的东西,但是仅当它想要将更多的负载加载到RAM中时,才有余地。因此,在使用很少的计算机上,几乎所有内容都可能在RAM中徘徊很长时间。但是在负担非常重的计算机上,操作系统将不断从RAM中丢弃需要很快恢复的内容。但是即使这样,某些事情还是被如此频繁地使用,它们不可能达到LRU阈值,因此即使大多数事情都被驱逐了,您也可能会在RAM中长时间存放某些事情。
第一季度的后续活动:在评论中回答您的问题:正确:libc.so
中没有任何内容可以定义main2.c
中的功能。正是由于这个原因,链接器需要从libc
复制printf()
的重定位和符号表信息,以便执行libc.so
时,{ {1}}也被加载。
详细信息:
main2
在libc.so
中可能被称为 ,但printf()
和中的声明了main2.c
在中定义printf()
[1]并编译到stdio.h
中; printf.c
可以编译,因为编译器可以看到libc.so
的签名(在main2.c
中),但是要构建printf()
(可执行文件), stdio.h
中已经编译的代码需要与main2
(中间目标文件)进行链接。 libc.so
通过复制导致执行main2.o
的引用来动态加载ld
来实现此目的。 [2]
[1] 编译器将在定义标准库函数的方式方面有所不同。 main2
有一个文件libc.so
,该文件定义了gcc
(实际上是对printf.c
的传递);其他编译器可能会做不同的工作-但库的全部目的是,您无需查看printf()
的定义和其他库函数;您只需要来自相应vfprintf()
文件的声明即可知道如何在您自己的printf()
文件中调用。
[2] 或,如果您构建静态链接的可执行文件,则代码(不仅是符号表)将从库文件复制到可执行文件中,即使在没有.h
文件的计算机上也可以运行该可执行文件。动态链接或静态链接对于构建给定的可执行文件是否更好取决于几个因素。