深入 C 语言和程序运行原理
于航
PayPal 技术专家
21121 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
深入 C 语言和程序运行原理
15
15
1.0x
00:00/00:00
登录|注册

28|程序可以在运行时进行链接吗?

基于 dlopen、dlsym、dlerror 和 dlclose
发生在程序运行中
基于 GOT 和 PLT
发生在程序执行前
内存资源浪费
二进制文件体积大
重复链接成本高
Linux 共享库的 soname 机制
dlclose 卸载共享库
dlsym 获取符号地址
通过 dlopen API 动态加载共享库
完成符号重定位后执行程序
动态链接器先于程序代码执行
再次调用时直接通过 GOT 访问
初次调用函数时完成符号重定位
包含特殊机器代码
协同 GOT 实现函数符号的延迟绑定
与 Text Segment 的相对距离固定
存放外部函数或变量的实际地址
不需要重定位内部引用地址
允许代码在进程 VAS 的任意位置执行
可以被多个进程共享
通过 -shared-fPIC 编译生成
使用 .so 后缀
运行时链接
加载时链接
解决静态链接的缺点
思考题
运行时链接的过程
加载时链接的过程
延迟绑定过程
过程链接表(PLT)
全局偏移表(GOT)
位置无关代码(PIC)
共享库(Shared Library)
动态链接的类型
动态链接的目的
动态链接

该思维导图由 AI 生成,仅供参考

你好,我是于航。
在上一讲中,我介绍了有关 Linux 下静态链接的内容。而这一讲,我们将继续程序的“链接”之旅,来看看我之前提到的另外两种链接类型,加载时链接与运行时链接。
实际上,加载时链接与运行时链接均可归为动态链接,只是在这两种方式中,程序进行链接的具体时刻有所不同。其中,加载时链接发生在程序代码被真正执行之前;而运行时链接则可发生在程序运行过程中的任意时刻。

为什么要使用动态链接?

在上一讲中,我已经简单介绍了静态链接与动态链接两者的区别。其实,动态链接技术出现的最重要目的,便是为了解决静态链接具有的一些明显缺点。试想,假设一个应用程序依赖于多个第三方模块提供的函数实现,而这些模块均以静态库(包含有多个目标文件)的方式提供。那么,每次想要使用它们的最新版本时,我们都需要显式地将程序与它们重新进行链接。对于大多数普通的应用使用者来说,这个过程所花费的成本当然是无法接受的。
另外,使用完全静态链接也会导致那些本可以被多次重用的通用功能函数,无法被统一“提取出来”,这便会导致程序的二进制可执行文件体积变大。并且,这些通用代码的副本会随着多个进程的运行,被多次加载到内存中,而这也极大地浪费了宝贵的内存资源。而动态链接技术的出现,便可以解决上述这些问题。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了动态链接技术的原理和应用。首先解释了动态链接的出现目的,以及动态链接相对于静态链接的优势。文章详细讲解了动态链接的基本原理,包括使用共享库的方法、位置无关代码(PIC)和全局偏移表(GOT)的重要作用。接着,文章通过实例分析了动态链接的执行过程,以及初次执行和再次访问时的流程。此外,文章还介绍了加载时链接和运行时链接的区别,以及运行时链接的实现方式和API。总的来说,本文通过深入的技术讲解,帮助读者全面了解了动态链接的原理和应用,以及相关的技术细节。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(6)

  • 最新
  • 精选
  • liu_liu
    老师,有几个问题想了解下: 1. 假设共享库 M,引用由应用程序定义的某个全局变量 g。而 A、B 程序都链接了 M,那么 M 中的 .got 是不是需要复制一份?因为 A、B 中 g 变量的虚拟地址不一样。 2. 关于 _dl_runtime_resolve 做符号重定位,是会遍历到所有依赖的动态库吗?如果两个动态库中都有这个符号,那么会定位到顺序靠前的动态库中的符号? 3. 如果第 2 点成立,那遍历动态库的顺序是根据链接时参数的顺序来的吗?

    作者回复: 这几个问题很棒!下面是回答: 1. 是这样的,每个进程的 VAS 中共享库 M 的内存映像内都有自己的 GOT Section,里面保存了不同的地址信息。在物理内存上看,Text Segment 中的数据是可以共享的,而 Data Segment 则是进程独立的。 2. 是的,通常动态链接器会默认使用第一个被 resolve 的符号,这个过程也被称为 “Symbol Interposition”。 3. 动态链接器通常会采用广度优先(breadth-first)的方式,按照可执行文件中 .dynamic Section 里 DT_NEEDED 条目内的记录顺序进行解析。

    2022-02-28
    6
  • 纳兰容若
    老师您好 有个问题请教一下 在图中的地址是不是画错了,一个是601008一个是6001008,还是地址之间有换算

    作者回复: 感谢指正!这边应该是图里的地址写错了,我来更新一下。这边这两个地址应该是完全相同的。

    2022-05-07
    2
  • 福利社
    现在程序的链接库越来越多,请问老师,有没有办法找出程序所有存在symbol interposition的函数及所在的动态库。

    作者回复: Runtime Interposition 实际上是动态链接器做出的一种选择。对于自己可以控制的代码部分,通常可以选择性地添加 static 关键字,来限制各个符号的作用域,使它们仅维持在当前编译单元。我查了一下,貌似没有发现比较好的方式可以直接暴露出链接过程中发生的 Symbol Interposition。有一种方式是自己写一个简单的脚本,通过使用 “nm” 命令遍历程序以及它的所有依赖动态库,以此来查看是否有重名的符号存在。符号类型可以通过输出内容的 Symbol Type 字段区分,具体可以参考这里:https://www.ibm.com/docs/en/zos/2.1.0?topic=scd-nm-display-symbol-table-object-library-executable-files。

    2022-03-03
    2
  • 谦谦
    老师你好,请问下,为什么编译应用程序的时候,共享库和应用程序要放在一起。假如我只知道共享库的名字,和运行时所在的路径。这种情况可以编译应用程序吗?

    作者回复: 可以的,比如对于 Clang 你可以通过 LD_LIBRARY_PATH 环境变量来设置共享库的查找路径。

    2022-08-26归属地:上海
  • 神佑小鹿
    假设共享库 M,引用由应用程序定义的某个全局变量 g。而 A、B 程序都链接了 M。。 这个关系很奇怪,这个应用程序是指的 A 和 B 么?? 如果是 A 和 B,这个依赖关系不是很怪么?

    作者回复: “这个应用程序是指的 A 和 B 么?” - 是的。 这里的例子只是为了帮助理解课程内容,不谈软件设计上的合理性,至少这种使用方式本身是合法的,因此现实情况中类似的场景也还是有的。

    2022-05-15
    3
  • 连瑞龙
    在Linux系统中,共享库(shared library)使用 soname(共享库的名字)机制来管理共享库的版本。soname是"Shared Object NAME"的缩写,它是在共享库中嵌入的标识符,用于指定库的版本信息。 soname机制的主要目的是在不同版本的共享库之间提供兼容性,以允许多个版本的共享库在系统上共存,而不会相互干扰。soname由以下两个部分组成: 1. **实际文件名(Real name):** 共享库的实际文件名,通常以`.so`为后缀。 2. **soname:** 共享库的名字,包含主版本号。soname一般形式为`lib<name>.so.<major>`,其中`<name>`是库的基本名字,`<major>`是主版本号。例如,`libexample.so.1`。 在共享库的构建和安装过程中,开发者通常会使用`-soname`选项来指定soname。例如: ```bash gcc -shared -o libexample.so.1.0 -Wl,-soname,libexample.so.1 example.o ``` 这个命令将生成一个名为`libexample.so.1.0`的共享库文件,并且指定其soname为`libexample.so.1`。这样,当程序链接到共享库时,会使用soname来查找和链接共享库,而不是直接使用实际文件名。 使用soname的主要优势包括: - **版本管理:** soname允许系统上存在多个版本的同一个共享库,每个版本都可以独立安装和管理。 - **向后兼容性:** 当共享库的API发生变化时,通过更新soname,可以确保新版本与旧版本兼容,从而防止因为API的变化而导致的程序崩溃。 - **符号冲突的解决:** 当多个共享库的实际文件名相同,但soname不同时,可以避免符号冲突,确保程序能正确链接到所需版本的库。 总之,soname机制在Linux系统中用于管理共享库的版本,提供了一种有效的方式来确保共享库的向后兼容性和版本管理。
    2024-01-09归属地:北京
收起评论
显示
设置
留言
6
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部