为什么静态和动态可链接库不同?

Tam*_*lei 28 language-agnostic linker loader

如果它们都包含已编译的代码,为什么我们不能在运行时加载"静态"文件,为什么我们不能在编译时链接动态库?为什么需要单独的格式来包含"独立"代码?什么需要存储哪个保证差异?

Mar*_*age 22

静态库是真正的库,因为它们包含目标文件库.每个目标文件通常是从单个源文件创建的,包含机器代码以及有关代码所需数据的信息.在链接步骤中,链接器将选择必要的目标文件并将它们组合成可执行文件.

机器代码的一个重要部分是跳转,调用和数据指针必须包含实际的内存地址.但是,如果目标文件需要在另一个目标文件中调用另一个函数,则它只能使用符号引用该函数.当链接器将目标文件组合成可执行代码时,符号引用将被解析并转换为实际内存地址.

动态库是可执行代码,可以加载到内存中并立即执行.在某些操作系统上,可能存在另外的步骤,其中通过将可执行代码移动到另一个位置来重新设置代码,并且这要求代码内的所有绝对地址被移位固定量.此操作仍然比组合目标文件和解析链接器完成的符号快得多.

把它们加起来:

  • 静态库包含一些可执行代码,它们使用符号来引用其他可执行代码段
  • 动态库(和可执行文件)包含现在放置在固定位置的可执行代码,使符号可以用实际内存地址替换

如果你曾试图链接一个合理大小的项目,你会注意到它需要花费很多时间,可能比你想要等待启动一个应用程序的时间长.这就解释了为什么你不能执行静态库.并且动态库已经过优化和剥离,除了可执行代码之外不包含任何内容,这使得它们不适合用作静态库.


Jer*_*fin 6

目标文件中的代码未链接.它包含对尚未解析的外部函数的隐式引用.

链接目标文件以创建DLL时,链接器会查看所有这些外部引用,并查找可满足它们的其他库(静态或动态).通过将该函数的主体(或其他)包含到DLL中来解析对静态库中的名称的引用.如果它引用动态库,则DLL和引用函数的名称都包含在DLL中.

最终,没有理由,这将是事实.从理论上讲,每次加载文件时都可以编写加载程序来完成所有这些操作.它基本上只是一个优化:链接器执行相对较慢的工作部分.剩下对DLL的引用,但它们被解决到加载器查找和加载目标文件(如果需要)并解析引用的函数相当快的程度.当链接器正在完成它的工作时,它会通过扫描很长的定义列表来找到你关心的那些,这会慢得多.


Die*_*Epp 5

注意:以下答案不是平台无关的,而是特定于基于ELF的系统和其他一些类似的系统。其他人可以填写其他系统的详细信息。

什么是静态库?

静态库是*.o归档中文件的集合。每个文件都可以包含对未定义符号的引用,链接器必须对此文件进行解析,例如,您的库可能具有对的引用printf。该库未提供有关在哪里printf可以找到任何指示的信息,预计链接器会在要求链接的其他一个库中找到它。

假设您的库包含以下代码:

read_png.o
write_png.o
read_jpg.o
write_jpg.o
resize_image.o
handle_error.o
Run Code Online (Sandbox Code Playgroud)

如果应用程序仅使用read_pngwrite_png,则其他代码段将不会加载到可执行文件中(handle_errorread_png和调用的除外write_png)。

我们无法在运行时加载静态库,因为:

  • 链接器不知道在哪里可以找到外部对象printf

  • 会很慢。动态库已针对快速加载进行了优化。

  • 静态库没有名称空间的概念。我无法定义自己的名称,handle_error因为它会与库的定义冲突。

什么是动态库?

ELF系统上的动态库是与可执行文件相同类型的对象。它还会导出更多符号,可执行文件只需要导出即可_start。动态库经过优化,因此可以将整个对象直接映射到内存中。

如果printf在动态库中有对的调用,则除了静态库的要求之外,还有一些其他要求:

  • 您必须指定具有的库printf

  • 您必须以一种特殊的方式调用该函数,以使链接程序为插入地址printf。在静态库中,链接器只能修改您的代码并直接插入地址,但是共享库则无法实现。

我们不想使用动态库静态链接,因为:

  • 我们不能仅链接动态库的一部分。即使我们的可执行文件从不调用read_jpg,它也会被包含在内,因为动态库是全有还是全无。

  • 即使很小,函数调用的额外开销也是浪费的。

摘要

编译看起来像这样:

Source  ==compile==>  Object  ==link==>  Executable / Shared Library
Run Code Online (Sandbox Code Playgroud)

静态库是一个充满了尚未链接对象的档案。还有很多工作要做。

共享库是链接的最终产品,可以随时加载到内存中。

静态库是最早发明的。如果两者是同时发明的,那么它们可能会更加相似。