在C语言中,链接和加载有什么区别?

17

动态库的链接和加载是否都发生在运行时?还是只有库的加载发生在运行时?


https://dev59.com/-HVC5IYBdhLWcg3wYQAp#311889 - paxdiablo
1
这不是一个完全相同的副本。 - Assaf Lavie
7个回答

21

请参考前面关于静态链接和动态链接之间区别的优点。假设您指的是动态链接,那么:

加载和(动态)链接都由链接器完成 - 在Linux和其他类Unix操作系统上,这是由/lib/ld.so执行的,这几乎在所有情况下都是由操作系统启动的实际程序。ld.so将您的应用程序- mygameBinary加载到内存中,然后从文件mygameBinary读取所需的动态链接库列表。

链接器ld.so会依次加载每个库到内存中,例如libc.solibpthread.solibopengl.so,并查看这些库可能需要哪些其他库,例如libm.so

一旦加载完成,就开始进行链接的过程,这是一个查看由一个库或应用程序导出的命名对象或函数,并被另一个库或应用程序导入的过程。然后,链接器更改各种引用和有时代码,以更新每个库中未链接的数据指针和函数调用的位置,使其指向实际的数据或函数。例如,在mygameBinary中对printf的调用一开始指向空白(实际上只是调用链接器),但在链接之后变成了跳转到libc中的printf函数。

一旦链接完成,应用程序就会启动,通过调用mygameBinary中的_start函数,然后调用main,你的游戏就开始了。

以这种方式进行动态链接是为了支持以下内容:

  • 发布应用程序后更新库,更改函数和数据的位置。
  • 同一个应用程序在不同操作系统版本上运行
  • 无法确定库或应用程序加载到内存的位置
  • 通过在多个应用程序之间共享使用的物理RAM减少核心大小。

一些操作系统在细节上有所不同,例如OSX和AIX都将某些库预装到内存中的固定位置。这意味着它们不需要被加载,只需链接即可,这可能会更快。

一些操作系统(如OSX和Linux)支持预链接(pre-linking),这是一个在你启动应用程序之前运行在你的系统上的脚本,它完成链接。当你启动它们时,你就不需要再链接它们了。这很重要,因为链接在启动应用程序时会占用相当多的计算机时间,有些应用程序可能会在一秒钟内启动多次,比如在应用程序构建过程中的gcccppas,或者在索引计算机数据时的过滤脚本(例如OSX的Spotlight)。


8

链接是将一些较小的可执行文件连接在一起,形成一个较大的可执行文件的过程。

加载是在执行之前将可执行文件加载到内存中的过程。


1
他在询问动态库,这种情况下链接不是将较小的“可执行文件”包含在一个更大的文件中的过程。 - Todd Gamblin

5

连接有两种类型:静态连接和动态连接。

静态连接发生在编译时,因此它发生在加载程序之前。使用静态连接时,您的程序使用的外部符号(例如函数名称)在编译时解析。

动态连接发生在运行时,因此它发生在加载程序时或加载后。使用动态链接时,符号可以在加载时解析,也可以在访问符号时运行时解析(延迟绑定)。后者更为常见。


2

这两个过程都发生在动态库的运行时。

首先,加载库及其所有依赖项(以及这些库的依赖项等)。然后,动态链接器解析已加载库中的符号。通常,这两个功能由同一软件实现;在Linux上,它是ld.so

静态库中的符号在链接时解析并包含在可执行文件本身中。但是,静态库可能具有未解决的符号,在运行时由动态库满足。

如何发生这种情况,名称如何散列,运行时解析符号的成本等都在How to Write Shared Libraries中进行了详细描述。


1

file01.c, file02.c --> 生成 --> file01.o, file02.o --> 这些 .o 信息被合并并放入一个单独的动态库中,即 lib1.a file11.c, file12.c --> 生成 --> file11.o, file12.o --> 这些 .o 信息被合并并放入一个单独的动态库中,即 lib2.a

现在,我有两个库最终链接在一起生成可执行文件(如 .elf 或 .mot 或 .fls)。将来自 lib1.a 和 lib2.a 的信息链接成一个单独的可执行文件的过程称为链接。

现在,我需要将其加载到内存中以运行它以查看最终可执行文件的行为。将最终可执行文件(如 .elf 或 .mot 或 .fls)加载到内存中以运行它的过程称为加载。

希望这能清楚地说明链接和加载的重要性(尽管定义不太恰当 :-)).


我知道链接和加载的过程...我需要知道它们中哪一个会先发生以及为什么? - Vijay
首先肯定是链接,这样才能得到最终的可执行文件,然后再加载执行。所以先进行链接,然后再加载。顺便说一下,抱歉回复晚了... :-) - wrapperm
除了动态库/链接的情况外,上面的答案说:“一旦加载完成,链接就开始了…” - undefined

-1

Windows和Unix系统在动态库方面采用完全不同的方法。

Windows DLLs没有被链接。因此,您无法在DLL之间共享静态对象。就像您地址空间中的一个单独程序。

Unix共享对象在运行时确实是“链接”的,就像同一项目的不同模块一样,执行符号解析。


nobugz: 我建议你查找“链接”条目以及符号解析的工作原理。你会明白为什么没有办法在 DLL 边界共享静态变量。 - Pavel Radzivilovsky

-1

动态链接和库加载都发生在运行时,但动态链接是在程序执行之前由系统链接器完成的。因此,例如,如果所需的库缺失,则无法执行程序。另一方面,库加载是由程序本身通过dlopen / LoadLibrary函数完成的。在这种情况下,加载过程由应用程序控制,可以处理错误等。


那么加载是什么时候发生的呢?如果是动态链接,它是在链接阶段之前吗? - Vijay
如果需要加载,库将在程序调用dlopen/LoadLibrary函数时加载。这可以在程序员想要的任何时候发生;) - el.pescado - нет войне

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接