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

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


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

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

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

把它们加起来:

  • 静态库包含使用符号来引用其他可执行代码片段的可执行代码片断
  • 动态库(和可执行文件)包含现在放置在固定位置的可执行代码,这些符号可以用实际内存地址替换
  • 如果你曾经试图链接一个合理大小的项目,你会注意到它花费的时间不是很多,可能比你想等待启动一个应用程序更长。 这就解释了为什么你不能执行静态库。 并且动态库已经过优化,并且除了可执行代码之外不含任何内容,这使得它们不适合用作静态库。


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

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

    最终,没有理由必须如此。 从理论上讲,每次加载文件时,都可以编写加载程序来完成所有这些操作。 这基本上只是一个优化:链接器做的工作相对较慢的部分。 对DLL的引用仍然存在,但是它们被解析为加载器能够快速找到并加载目标文件(如有必要)并解析引用的函数。 当链接器正在完成它的工作时,它通过扫描长列表定义来找到你关心的内容,这会比较慢。


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

    什么是静态库?

    静态库是归档中的*.o文件的集合。 每个文件都可以包含对未定义符号的引用,这些引用必须由链接器解析,例如,您的库可能有对printf的引用。 该库没有提供任何有关printf被发现的地方的信息,预计链接器会在要求链接的其他库中找到它。

    假设你的库包含下面的代码:

    read_png.o
    write_png.o
    read_jpg.o
    write_jpg.o
    resize_image.o
    handle_error.o
    

    如果应用程序只使用read_pngwrite_png ,然后代码的其他部分将不会装入可执行文件(除handle_error ,这是从所谓的read_pngwrite_png )。

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

  • 链接器不知道在哪里找到外部对象,例如printf

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

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

  • 什么是动态库?

    ELF系统上的动态库与可执行文件是同一类型的对象。 它也导出更多的符号,一个可执行文件只需要导出_start 。 动态库被优化,所以整个事情可以直接映射到内存中。

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

  • 你必须指定哪个库有printf

  • 你必须以特殊的方式调用函数,让链接器插入printf的地址。 在静态库中,链接器可以直接修改代码并插入地址,但这对于共享库是不可行的。

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

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

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

  • 概要

    编译看起来像这样:

    Source  ==compile==>  Object  ==link==>  Executable / Shared Library
    

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

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

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

    链接地址: http://www.djcxy.com/p/73313.html

    上一篇: Why are static and dynamic linkable libraries different?

    下一篇: Why aren't #define'd constants known to debugger?