动态库的链接和加载是否都在运行时发生? 或者只是在运行时加载库?
答案 0 :(得分:18)
请参阅前面关于静态链接和动态链接之间区别的非常好的观点。假设您指的是动态链接,那么:
加载和(动态)链接都是由链接器完成的 - 在linux和其他Unix上相同,这是由/lib/ld.so
完成的,这是几乎所有情况下操作系统启动的实际程序。 ld.so
依次加载您的应用程序 - mygameBinary
到内存中,ld.so
然后从文件mygameBinary
读取动态链接库列表需要。
然后,链接器ld.so
依次将每个库加载到内存中,例如: libc.so
,libpthread.so
,libopengl.so
,并查看这些可能需要的其他库,例如: libm.so
。
加载完成后,链接开始,查看由一个库导出的命名对象或函数的过程应用程序,以及另一个库或应用程序导入。然后,链接器更改各种引用,有时还会更新代码以更新每个库中的未链接数据指针和函数调用,以指向实际数据或函数所在的位置。例如,printf
中对mygameBinary
的调用开始时没有指向任何内容(实际上它只是调用链接器),但是在链接之后跳转到printf
中的libc
函数}。
此链接完成后,启动应用程序,方法是调用_start
中的mygameBinary
功能,然后调用main
,然后开始游戏。
以这种方式进行动态链接是必要的,以支持以下内容:
某些操作系统的细节不同,例如OSX和AIX都将某组库预先加载到内存中的固定位置。这意味着它们不需要加载,只需链接,这可能更快。
某些操作系统(如OSX,有时还支持Linux)支持预链接,这是一个脚本在启动它们之前在系统上的应用程序上运行并进行链接的过程。启动它们时,您无需链接它们。这很重要,因为在您启动应用时,链接会占用相当多的计算机时间,而某些应用可能会在一秒钟内多次启动,例如gcc
,cpp
和as
期间索引计算机数据时的应用程序构建过程或过滤脚本(OSX Spotlight)。
答案 1 :(得分:6)
链接是将一些较小的可执行文件作为单个较大的可执行文件连接在一起的过程。
加载是在执行之前将可执行文件加载到内存中。
答案 2 :(得分:3)
有两种类型的链接:静态链接和动态链接。
静态链接在编译时发生,因此它在加载程序之前发生。使用静态链接,程序使用的外部符号(例如函数名称)将在编译时解析。
动态链接在运行时发生,因此它发生在加载程序之后或加载时。通过动态链接,符号在加载时或在访问符号时的运行时解析(延迟绑定)。后者更为常见。
答案 3 :(得分:1)
两者都在运行时发生在动态库中。
首先,加载库及其所有依赖项(以及这些库的依赖项等)。然后动态链接器解析已加载库中的符号。通常这两个功能都是由同一个软件实现的;在Linux上它是ld.so。
静态库中的符号在链接时解析并包含在可执行文件本身中。但是,静态库可能具有未解析的符号,这些符号在运行时由动态库满足。
在How to Write Shared Libraries中有深入的描述如何发生这种情况,如何对名称进行哈希处理,在运行时解析符号的成本等等。
答案 4 :(得分:1)
file01.c,file02.c - >产生 - > file01.o,file02.o - >这些.o信息被分组并放入一个动态库,即lib1.a file11.c,file12.c - >产生 - > file11.o,file12.o - >这些.o信息被分组并放入一个动态库,即lib2.a
现在,我有2个库最终链接在一起以生成可执行文件(如.elf或.mot或.fls)。将lib1.a和lib2.a中的信息链接起来形成单个可执行文件的过程称为链接。
现在,我需要将其加载到内存中以便运行它以查看最终可执行文件的行为。将最终可执行文件(如.elf或.mot或.fls)加载到内存中以便运行的过程称为加载。
我希望这可以清除链接和加载的重要性(但定义不合适: - ))。
答案 5 :(得分:-1)
Windows和Unix系统使用完全不同的动态库方法。
Windows DLL未链接。因此,您无法跨DLL共享静态对象。它就像你地址空间中的一个单独的程序。
Unix共享对象在运行时实际上是“链接”的,就像同一个项目的不同模块一样,执行符号解析。
答案 6 :(得分:-1)
动态链接和库加载都在运行时发生,但动态链接在程序执行之前完成,由系统链接器完成。因此,例如,如果缺少必需的库,则无法执行程序。另一方面,库加载是由程序本身通过dlopen / LoadLibrary函数完成的。在这种情况下,加载过程由应用程序控制,例如可以处理错误。