【Linux系统】动态库和静态库 动态库加载

news2024/11/27 0:31:06

认识动态库静态库

我们有没有使用过库呢?-- 用过c、c++的标准库

c的各种函数,c++的各种STL容器,我们使用他们内部必须得有具体实现。

Linux:   .so(动态库) .a(静态库)  Windows: .dll(动态库) .lib(静态库)

 库是拿来给别人使用的,所以库里面必然没有main函数,库名是去掉前缀lib和后缀.so

静态库

我们知道若干的.o文件能够链接成一个可执行文件。

静态库一般是这些若干目标二进制文件(.o)打包而成。我们一般用gcc -c选项生成.o文件。

一个完整的库需要静态库或动态库加上头文件。

头文件是一个手册,提供函数的声明,告诉用户怎么用。

.o提供实现,我们只需要补上一个main.c,调用头文件提供的方法,然后和.o进行链接,就能形成可执行文件。

我们一般用ar -rc libmyc.a *.o来打包.o文件形成静态库。

 我们把.o文件可以删除了。

 直接执行后是找不到定义的,也就是说gcc/g++是不认识这个库的,gcc/g++默认是认识C/C++库的,但libmyc.a是别人写(第三方提供的),gcc//g++不认识!!!

使用gcc main.c libmyc.a

 我们以后使用库文件肯定是放在某一个目录中去,头文件和静态库分别放到对应目录文件中去。

 我们把头文件放到./mylib/include中,libmyc.a放到./mylib/lib中去。

然后执行gcc main.c libmyc.a

把静态库写入自己指定的文件里。

gcc main.c -I ./mylib/include/ -L ./mylib/lib/ -l myc

其中-I选项: 指定用户自定义头文件路径

-L选项:指定用户自定义库文件路径

-l选项:指行确定的第三方库名称(去掉前缀.so和后缀.a)

动态库

动态库的制作与静态库略有区别,首先产生.o文件的选项就不同,增加了选项-fPIC(与位置无关码)

 然后打包.0文件执行就不是静态库那样执行ar命令,而是执行gcc带选项-shared

 动态库制作成功,把动态库移动我们的库文件中去。

 执行main.c

 

 

为什么会这样?因为 你告诉给了gcc/g++编译器,但你没告诉给操作系统!!!

动态库,因为程序在运行的时候要找到动态库加载并运行!

静态库为什么没这个问题?编译期间,已经将库中的代码,拷贝到我们的可执行程序内部了,加载就和库没有关系了!!!

怎么解决?五种方法来解决!!!

1.安装到系统

可以把.so文件拷贝到系统目录下/lib64

 先切换到root用户下,因为是系统文件,子用户没有权限。

2.建立软链接

在系统路径下建立软链接!!!

 

3.命令行导入环境变量

系统会搜索环境变量的路径!!!

由于这里导入的环境变量是内存级的,是无法永久生效的,重启系统操作系统会加载新的环境变量的内容,而这些使用命令临时导入的环境变量就不存在了!!!

4.修改.bashrc配置文件,让环境变量永久生效

修改配置文件 

 

重启操作系统依然可以正常链接

 

5./etc/ld.so.conf.d 新增动态库搜索的配置文件,ldconfig

 

 切换root创建我们的配置文件。

写入动态库链接路径即可

 需要使用ldconfig用于配置共享库缓存,以便运行时正确的加载动态库。

 

因为gcc在不使用static选项时默认使用动态库。

 此时默认连接的是动态库,如果你没有使用-static,并且只提供.a,只能静态链接当前的.a库,其他库正常动态链接。

-static的意义是什么?必须强制的使用-static将我们的程序进行静态链接,这就要求我们链接的任何库,都必须提供对应的静态库版本。

动态库加载 -- 可执行程序和地址空间

因为静态库是把库中的代码拷贝到可执行程序中了,所以就无需加载!!!

所以不需要考虑静态库。

我们知道一个进程创建要同时创建task_struct, 地址空间,页表来与内存进行关系映射,在地址空间中有一块共享区,我们就需要在动态库加载之后,要映射到当前进程的堆栈之间的共享区,所以动态库也叫共享库。

我们知道c语言标准库就一直在内存中保存,因为我们在编译很多c语言程序时,甚至我们的指令都是用c语言写的,但都链接的是同一个库,这是怎么做到他们可能被映射到共享区的任意区域,仍然能够很好的找到对应的函数执行!!!

我们的可执行程序,编译成功,没有加载运行,二进制代码中有“地址”吗?

 有地址!!!

ELF格式的可执行程序,二进制是有自己的固定格式的,elf可执行程序的头部,可执行程序的属性

可执行程序编译之后,会变成很多行汇编语句,每条汇编语句都有他的地址。

那如何编址?

从000...000 --- ffffff...ffff这种顺序编址方式,我们叫为平坦模式,

上方就是这种模式,其实是一种虚拟地址,又叫逻辑地址!!!

ELF + 加载器可以知道各个区域的起始和结束地址,main函数的入口地址!!!

我们知道进程 = 内核数据结构 + 代码和数据,那么操作系统应该是先创建内核数据结构,然后再加载代码和数据,还是反过来呢?当然是第一种方式!!!

在我们CPU中有很多寄存器,其中有一个类似于pc指针的寄存器,

这个pc指针里面存放的是正在执行指令的下一跳指令的地址,pc指向哪里,CPU就执行哪里的代码!!!

 mm_struct是结构体对象,成员变量呢?

像code_start,code_end...global_start初始值从哪来呢?

从可执行程序来!!!

所以结论:虚拟地址空间概念,不是OS独有的,而是要有OS,编译器,加载器

 1.进程创建阶段,初始化地址空间,让CPU知道main函数入口地址

2.加载每一行代码和数据,就都有了物理地址,自己的虚拟地址自己也知道,然后就可以构建映射了!!!

库被映射到虚拟地址空间的什么位置重要吗?

由于可执行程序汇编代码是平坦模式,所以从0开始,那么每一行代码对应的地址就可以作为偏移量了!!!

库中代码被加载到内存中会有对应物理地址对应,而虚拟地址代表偏移量,那么,在地址空间与内存通过页表映射时就拿到了该行代码在地址空间的虚拟地址,而代码自带的地址可以是一种偏移量,那如何找到我们要执行的代码块,只需要让虚拟地址空间的初始位置 + 偏移量(虚拟地址)即可求得我们要执行代码的那一行。

我们可能不知道虚拟地址空间的共享区初始位置,但偏移量是确定的,所以无论初始位置在哪,总能找到我们想要的代码行!!!

所以虚拟地址空间的位置不重要!!!

即与地址无关

库函数调用其实,也是在我的地址空间返回内来回跳转!

如果库没有加载???OS可以让进程知道!!!

库也要先描述,在组织,被OS管理!

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

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

相关文章

Spring源码十六:Bean名称转化

在上一篇Spring源码十五:Bean的加载 中我们通过前面的案例方法,找到了Spring真正开始创建Bean的入口,也就是doGetBean方法。该方法是Spring框架中Bean创建与获取的核心逻辑,实现了复杂的Bean生命周期管理。通过单例缓存、合并Bean…

文章解读与仿真程序复现思路——太阳能学报EI\CSCD\北大核心《计及电-热-氢负荷与动态重构的主动配电网优化调度》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【双一流高校主办,Springer-LNICST出版,EI稳定检索】2024年应用计算智能、信息学与大数据国际会议(ACIIBD 2024,7月26-28)

2024年应用计算智能、信息学与大数据国际学术会议(ACIIBD 2024)将于2024年7月26-28日在中国广州举办。会议将聚焦于计算智能及其应用、信息、大数据等相关的研究领域, 广泛邀请国内外知名专家学者,共同探讨相关学科领域的最新发展…

Maya崩溃闪退常见原因及解决方案

Autodesk Maya 是一款功能强大的 3D 计算机图形程序,被电影、游戏和建筑等各个领域的设计师广泛使用。然而,Maya 就像任何其他软件一样可能会发生崩溃问题。在前文中,小编给大家介绍了3ds Max使用V-Ray渲染时的崩溃闪退解决方案: …

电路基础知识汇总

1.0 串连,并联,混连 串联的定义 电路串联是一种电路元件的连接方式,其中各个元件沿着单一路径互相连接,形成一个连续的链。在串联电路中,每个节点最多只连接两个元件,这意味着电流只有一条路径可以通过整个…

“来来来,借一步说话”,让前端抓狂的可视化大屏界面。

可视化大屏的前端开发难度要远远高于普通前端,尤其是当设计师搞出一些花哨的效果,很容易让UI和前端陷入口水大战中。 可视化大屏的前端开发相比普通前端开发的难度要高,主要是因为以下几个方面: 1. 数据量大: 可视化…

01:spring

文章目录 一:常见面试题1:什么是Spring框架?1.1:spring官网中文1.2:spring官网英文 2:谈谈自己对于Spring IOC和AOP的理解2.1:IOCSpring Bean 的生命周期主要包括以下步骤: 2.2&…

STM32-输入捕获IC和编码器接口

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. 输入捕获IC1.1 输入捕获IC简介1.2 频率测量1.3 输入捕获通道1.4 主从触发模式1.5 输入捕获基本结构1.6 PWMI基本结构 2. 输入捕获库函数及代码2.1 输入捕获库函数2.2 6-6 输入捕获模式测频率2.2.1 硬件连接2.2.2 硬…

DevEco Studio无法识别本地模拟器设备的解决方法

目录 场景 解决办法 方式1 方式2 场景 有很多小伙伴遇到过安装了手机模拟器, 但是开发工具设备栏不识别手机设备的问题, 如下图,明明模拟器都安装了,并启动, 但为什么设备栏不显示呢? 解决后的截图,应该是这样(其实跟 android 类似 )

拓扑排序,PageRank(markov),实对称矩阵等

拓扑排序 多件事情有先后顺序,如何判断哪个先哪个后 拓扑排序算法: 1.读入图时,需要记录每个顶点的入度,以及相邻的所有顶点 2.将入度为0的顶点入队(先进先出) 3.取出队首元素a,&#xf…

检测到弱密码:并非所有密码套件均支持完全前向保密解决方案

问题 检测到弱密码:并非所有密码套件均支持完全前向保密(弱密码套件 - ROBOT 攻击:服务器支持易受攻击的密码套件) 背景介绍 HTTP 协议自身没有加密机制,但可以通过与 TLS (Transport Layer Security) / SSL (Secur…

QThread moveToThread的妙用

官方文档描述 总结就是移动到线程的对象不能有父对象,执行start即起一个线程,示例是将myObject移动到主线程中。QT中这种方式起一个线程是非常简单的。 示例描述以及代码 描述往Communicate线程中频繁添加任务,等任务结束的时候统计计算的结…

用C#调用Windows API向指定窗口发送按键消息详解与示例

文章目录 1. 按键消息的定义及功能2. 引入所需的命名空间3. 定义Windows API函数4. 定义发送消息的方法5. 获取窗口句柄6. 调用API发送按键消息7. 使用示例注意事项总结 在C#中调用Windows API向指定窗口发送按键消息是一种常见的操作,这通常用于自动化脚本、游戏辅…

中国科学技术大学发布了2024年少年班录取名单

7月7日,中国科学技术大学发布了2024年少年班录取名单公示,来自上海的12岁“小孩哥”刘尧进入名单。 据澎湃新闻此前报道,刘尧是因为此前通过了中科大少年班的校测考试,提前拿到了“高考体验券”。他所在的上海市实验学校&#xff…

Vue3+.NET6前后端分离式管理后台实战(二十九)

1,Vue3.NET6前后端分离式管理后台实战(二十九)

go语言Gin框架的学习路线(六)

gin的路由器 Gin 是一个用 Go (Golang) 编写的 Web 框架,以其高性能和快速路由能力而闻名。在 Gin 中,路由器是框架的核心组件之一,负责处理 HTTP 请求并将其映射到相应的处理函数上。 以下是 Gin 路由器的一些关键特性和工作原理的简要解释…

【Unity2D 2022:Particle System】添加拾取粒子特效

一、创建粒子特效游戏物体 二、修改粒子系统属性 1. 基础属性 (1)修改发射粒子持续时间(Duration)为3s (2)取消勾选循环(Looping) (2)修改粒子存在时间&…

《梦醒蝶飞:释放Excel函数与公式的力量》9.4 NPV函数

9.4 NPV函数 NPV函数是Excel中用于计算净现值的函数。净现值(Net Present Value, NPV)是财务管理和投资决策中常用的指标,用于评估投资项目的价值。NPV表示的是未来一系列现金流的现值总和减去初始投资后的余额。 9.4.1 函数简介 NPV函数通…

【位运算】基础算法总结

目录 基础位运算给一个数n,确定它的二进制表示的第x位是0还是1将一个数n的二进制表示的第x位修改成1将一个数n的二进制表示的第x位修改成0位图思想(哈希表)提取一个数(n)二进制表示中的最右侧的1(lowbit&am…

【AI资讯】可以媲美GPT-SoVITS的低显存开源文本转语音模型Fish Speech

Fish Speech是一款由fishaudio开发的全新文本转语音工具,支持中英日三种语言,语音处理接近人类水平,使用Flash-Attn算法处理大规模数据,提供高效、准确、稳定的TTS体验。 Fish Audio