通俗举例讲解动态链接、静态链接

news2025/2/26 2:54:21

参考动态链接 - 知乎

加上我自己的理解,比较好懂,但可能在细节方面有偏差,但总体是一致的

静态链接的背景

静态链接使得不同的程序开发者和部门能够相对独立的开发和测试自己的程序模块,从某种意义上来讲大大促进了程序开发的效率,原先现在程序规模也随之扩大。
但静态链接的缺点也暴露出来:浪费内存、磁盘空间、模块更新困难(耦合性太强)。

内存与磁盘空间

静态链接在计算机早期还是比较流行的,但是到了后面,其缺点也非常明显。比如浪费内存和磁盘空间,更新模块困难等。

一个文件的转换进程

hello.c(源程序[文本])->预处理器(cpp)->hello.i(修改了的源程序[文本])->编译器(ccl)->hello.s(汇编程序[文本])->汇编器(as)->hello.o(可重定位目标程序[二进制])->链接器(ld)->hello(可执行目标程序[二进制])

只需要注意:

hello.c:源文件

hello.o:由hello.c编译而来

hello(可执行目标程序[二进制]),最终执行文件。

比如我有a.cpp ,a.h,b.cpp c.cpp四个文件

a.cpp 定义了一个函数sayHello

#include <iostream>
void sayHello(){
    std::cout<<"hello world!";
}

a.h

#ifndef UNTITLED1_A_H
#define UNTITLED1_A_H

void sayHello();

#endif //UNTITLED1_A_H

b.cpp 调用了a的函数sayHello

#include "a.h"
int main(){
    sayHello();
}

c.cpp 调用了a的函数sayHello

#include "a.h"
int main(){
    sayHello();
}

静态链接

如果运行b那么就会结合b.o,以及其调用的a.o生成可执行文件。c运行会另外调用 c.o,a.o生成可执行文件,此时可执行文件可以认为长这样

#include <iostream>
void sayHello(){
    std::cout<<"hello world!";
}
int main(){
    sayHello();
}

此时a.o重复了两次,但这两个a.o保存了相同的内容,浪费内存和磁盘。

程序开发与发布

静态链接另一个问题是对程序的更新,部署和发布也会很麻烦,我如果在a中更新了sayHello,那么生成的b,c可执行文件里的sayHello还是老的,需要重新连接,很麻烦耦合度很高。

程序有任何模块更新,整个程序就要重新链接,发布给用户,

动态链接

dll文件和so文件

dll文件和so文件都是动态链接库,也叫共享对象文件

动态链接原理

动态链接库就是将程序模块相互独立的分隔开来,形成独立的文件,不再将它们静态地链接到一起。简单而言就是对那些组成程序目标文件的链接,等到程序运行时才进行链接,也就是把链接的过程推迟到运行时才进行,这就是动态链接的基本思想

动态链接没有提前链接的过程,但一般文件都是动态和静态链接结合使用,也有生成可执行文件这一步。

比如我编译a.cpp为共享对象文件a.so,还有a.h

b.cpp为c.o,此时我运行生成可执行文件,生成时侦测到sayHello为动态链接的实现,所以就不执行链接(如果侦测到为静态文件,那么就还是老样子进行链接)

b可执行文件执行时,遇到sayHello,就去动态库so中找这个函数的实现位置,这个找的位置有几类,我们经常用的是一个环境变量,叫LD_LABRARY_PATH,假设这里找到了,找到之后就将a.so加载到内存,链接,进行执行。

c执行时再用到a.so,此时a.so以及被加载到了内存中,所以不用再重新加载了,直接链接就能使用了。

那也就说明了动态链接的其他特点:

动态运行b.cpp之前必须要有a.so和a.h才能运行,所需的动态库本地必须齐全。

动态链接库的存储位置以及名称

lib文件的名称,要和头文件相呼应,但有些库文件并不总是和头文件相呼应,连接器也不是通过头文件名来搜寻库文件的,而是根据将所有要搜寻路径库文件按优先级列出来,然后一个一个查找。

 比如

cudnn.h对应libcudnn.so

cudnn_adv_infer.h对应libcudnn_adv_infer.so等等

一般so文件会存在lib下,头文件存在include下

如cuda11.6

 

 可以看到

再比如我们c++原生的一些实现

头文件也是在include下,可以看到我们的老熟人头文件iostream等等

模块

静态链接中,整个程序最终只有一个可执行文件,它是一个不可以分割的整体,但是在动态链接下,一个程序被分成了若干个文件,有程序的主要部分,即可执行文件(Program1)和
程序所依赖的共享对象(Lib.so),很多时候把这些部分叫做模块,即动态链接下的可执行文件和共享对象都可以看做是程序的一个模块

当程序模块Program1.c被编译成Program1.o时,编译器还不不知道foobar函数的地址,当链接器将Program1.o链接成可执行文件时,这时候链接器必须确定Program1.o中所引用的foobar函数的性质。

  • 如果foobar是一个定义与其它静态目标模块中函数,那么链接器将会按照静态链接的规则,将Program1.o中的foobar地址引用重定位
  • 如果foobar是一个定义在某个动态共享对象中的函数,那么链接器就会将这个符号的引用标记为一个动态链接的符号,不对它进行地址重定位,把这个过程留到装载时再进行

程序如何找到用到的动态库以及查看用到的动态库

动态库的搜索顺序如下:

  • LD_PRELOAD环境变量指定库路径
  • -rpath链接时指定路径
  • LD_LIBRARY_PATH环境变量设置路径
  • /etc/ld.so.conf配置文件指定路径
  • 默认共享库路径,/usr/lib,lib

应该就是按顺序一个一个寻找,直到找到满足要求的实现的动态库为止。

程序是如何找到动态库的? | 守望的个人博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/427451.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NPC 也有了生命?当 ChatGPT 注入游戏你能想象吗

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; 目录引言&#xff1a;西部世界元宇宙&#xff0c;还记得吗ChatGPT 的世界&#xff1f;下图就是一个 ChatGPT 小镇&#xff1a; 引言&#xff1a;西部世界 《西部世界》以一个虚构的游戏般的“西部世界”为背景&am…

springboot验证码生成及验证功能

1.easy-captcha工具包 生成验证码的方式有许多种&#xff0c;这里选择的是easy-captcha工具包。 github开原地址为&#xff1a;easy-captcha工具包 其支持Java图形验证码&#xff0c;支持gif、中文、算术等类型&#xff0c;可用于Java Web、JavaSE等项目。 2添加依赖 首先需…

SQL Server的死锁说明

死锁指南一、了解死锁二、检测并结束死锁2.1、可能死锁的资源三、处理死锁四、最大限度地减少死锁4.1、以相同的顺序访问对象4.2、避免事务中的用户交互4.3、保持交易简短且在一个批次中4.4、使用较低的隔离级别4.5、使用基于行版本控制的隔离级别4.6、使用绑定连接4.7、停止事…

【云原生|Docker】04-docker的资源限制

目录 前言 容器的生命周期 1. 容器的启动过程 2. 容器的生命周期 ​编辑 内存限制 1. 内存限制的相关参数 2. 内存限制方式 2.1 设置-m,--memory&#xff0c;不设置--memory-swap 2.2 设置-m,--memorya&#xff0c;--memory-swapb&#xff0c;且b >a 2.…

本地从0搭建Stable Diffusion WebUI及错误记录

从0开始搭建本地Stable Diffusion WebUI环境 一.环境配置 1.使用的电脑配置 系统Windows10处理器英特尔 i7内存24GB显卡NVIDIA GTX 1060(6GB) 2.镜像源 阿里云 清华大学 中国科技大学 3.电脑环境变量配置 我的电脑–属性–高级系统设置–系统属性(高级)–环境变量 新建…

spring框架注解

3.Spring有哪些常用注解呢&#xff1f; Spring常用注解 Web: Controller&#xff1a;组合注解&#xff08;组合了Component注解&#xff09;&#xff0c;应用在MVC层&#xff08;控制层&#xff09;。 RestController&#xff1a;该注解为一个组合注解&#xff0c;相当于Con…

首个ChatGPT开发的应用上线;ChatMind思维导图工具;中文提示词大全;Copilot平替 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 『一本与众不同的AI绘本』ChatGPT 编写故事 Midjourney 绘制插图 作者的女儿特别喜欢迪士尼动画《海洋奇缘》里的主人公莫阿娜&#…

Mybatis分解式查询

目录 一、Mybatis一对多分解式查询 1. 新增持久层接口方法 2. 新增映射文件对应的标签 3. 新增测试方法 4. 运行效果 二、Mybatis一对一分解式查询 1. 新增持久层接口方法 2. 新增映射文件对应的标签 3. 新增测试方法 4. 运行效果 三、Mybatis延迟加载 1. 开启延迟加…

超实用的十个超级实用事半功倍的Python自动化脚本

一淘模板 56admin.com在日常的工作学习当中&#xff0c;我们总会遇到各式各样的问题&#xff0c;其中不少的问题都是一遍又一遍简单重复的操作&#xff0c;不妨直接用Python脚本来自动化处理&#xff0c;今天小编就给大家分享十个Python高级脚本&#xff0c;帮助我们减少无谓的…

【数据结构与算法】栈的实现(附源码)

目录 一.栈的概念和结构 二.接口实现 A.初始化 Stackinit 销毁 Stackdestroy 1.Stackinit 2.Stackdestroy B.插入 Stackpush 删除 Stackpop 1.Stackpush 2.Stackpop C.出栈 Stacktop D. 栈的有效元素 Stacksize 判空 Stackempty 1.Stacksize 2.Stackempty …

Flink进阶篇-CDC 原理、实践和优化采集到Doris中

简介 基于doris官方用doris构建实时仓库的思路&#xff0c;从flinkcdc到doris实时数仓的实践。 原文 Apache Flink X Apache Doris 构建极速易用的实时数仓架构 (qq.com) 前提-Flink CDC 原理、实践和优化 CDC 是什么 CDC 是变更数据捕获&#xff08;Change Data Captur…

Spring《三》DI依赖注入

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; 上一篇&#xff1a;Spring《二》bean的实例化与生命周期 下一篇&#xff1a;敬请期待 目录一、setter注入&#x1f349;1.注入引用数据类型2.注入简单数据类型二、构造器注入&#x1f34a;1.注入引用数据类型2.简单数…

数据挖掘(2.3)--数据预处理

目录 三、数据集成和转换 1.数据集成 2.数据冗余性 2.1 皮尔森相关系数 2.2卡方检验 3.数据转换 四、数据的规约和变换 1.数据归约 2数据离散化 三、数据集成和转换 1.数据集成 数据集成是将不同来源的数据整合并一致地存储起来的过程。 不同来源的数据可能有不同…

Qt优秀开源项目之十七:QtPromise

QtPromise是Promises/A规范的Qt/C实现。该规范的译文见附录。 QtPromise基于Qt5.6及以上版本&#xff0c;当然也包括Qt6。 github地址&#xff1a;https://github.com/simonbrunel/qtpromise 新手导航&#xff1a;Getting Started | QtPromise API手册&#xff1a;API Referenc…

详解Spring、SpringBoot、SpringCloud三者的联系与区别

一、Spring二、Spring Boot三、Spring Cloud四、三者的关系一、Spring Spring 是一个轻量级的Java 开发框架&#xff0c;主要依存于SSM 框架&#xff0c;即Spring MVC Spring Mybatis&#xff0c;定位很明确&#xff0c;Spring MVC主要负责view 层的显示&#xff0c;Spring …

Scala 一文搞定

第一节&#xff1a;概述为什么学习Scala ?Apache Spark 是专为大规模数据快速实时处理的计算引擎/内存级大数据计算框架。Apache Spark 是由Scala 语言编写。Scala 与Java 关系总结三点:java 编译器与Scala 编译器可以相互使用。Java SDK 的类库可以被Scala使用&#xff0c;Sc…

理解什么是sql注入攻击 + xss攻击 + cors 攻击

SQL注入 SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串&#xff0c;最终达到欺骗服务器执行恶意的SQL命令。 SQL注入攻击的总体思路: 寻找到SQL注入的位置判断服务器类型和后台数据库类型针对不同的服务器和数据库特点进行SQL注入攻击 SQL注入…

Cookie和Session的工作流程及区别(附代码案例)

目录 一、 HTTP协议 1.1 为什么HTTP协议是无状态的&#xff1f; 1.2 在HTTP协议中流式传输和分块传输编码的区别 二、Cookie和Session 2.1 Cookie 2.2 Session 2.3 Cookie和Session的区别 三、servlet中与Cookie和Session相关的API 3.1 HttpServletRequest 类中的相关方…

CSRF漏洞的概念、利用方式、防御方案

CSRF漏洞1.CSRF的概念1.1 什么是CSRF&#xff1f;1.2 基本攻击流程2.CSRF攻击实现2.1 靶场练习2.2 CSRFXSS组合拳2.2.1 攻击页面部署2.2.2 构造恶意xss语句&#xff0c;实现重复生效的CSRF3. CSRF攻击的防御**3.1 只使用JSON API****3.2 验证HTTP Referer字段****3.3 在请求地址…

【Spring源码】Spring事务原理

目录 1、什么是事务 2、Spring事务基本概念 2.1、基础配置 2.1.1、Spring事务的基础配置 2.1.2、Spring事务的传播特性 2.1.3、Spring事务的隔离级别 2.2、基本原理 3、事务嵌套 3.1、PROPAGATION_REQUIRED 3.2、PROPAGATION_REQUIRES_NEW 3.3、PROPAGATION_SUPPORTS…