动静态库-动态库加载

动静态库

  • 前言
    • 引入
  • 一、静态库
    • 1. 创建静态库
      • ①原理
      • ②创建
    • 2. 使用静态库
      • ①借助编译选项
      • ②只需要带库名
    • 3. 小结
  • 二、动态库
    • 1. 创建动态库
    • 2. 使用动态库
  • 三、 动态库加载原理——进程地址空间
    • 1. 地址
      • ①程序没有被加载前的地址
      • ②程序加载后的地址
    • 2. 原理
      • ①动态库的地址
      • ②原理

前言

讲编译工具gcc时,讲到链接库,其中说静态链接和动态链接的相关知识,并且介绍了一些拓展命令,eg:od/file/ldd/readelf

接下来,目标:深入理解动静态库

引入

当我们想把我们写的代码给别人使用有两种方式:

  1. 直接把我们写的源文件和头文件给别人。
  2. 把源代码打包成库,加上头文件给别人。(库+.h)

优劣:

  • 第一种:相当于把底层的东西直接暴露给使用者。
  • 第二种:相当于只把使用说明(头文件)展示给使用者,使用者只知道如何调用方法,而不知道底层具体如何实现。

一、静态库

1. 创建静态库

①原理

生成库

  1. 静态库其实就是一堆.o文件打包形成
  2. 要先把源文件提前编译成目标文件
  3. 所以生成的库,人是读不出来的。

②创建

创建静态库

2. 使用静态库

开发者的库(xxx.a) + 使用者编写的代码(xxx.c) = 可执行程序(xxx.exe)

①借助编译选项

测试代码:
测试代码

  1. 直接编译一下试试:
    运行结果
    结果:运行失败
    结论:我们这里测试的头文件,不在系统指定的目录下(usr/include),所以gcc找不到这个头文件.
  1. 告诉编译器,头文件的位置。使用-I选项,后面跟头文件所在路径即可
    命令:gcc main.c -I ./lib/include
    运行结果
    结果:运行失败
    结论:这里不再是找不到头文件了,使用我们指定头文件路径这个是正确的,但是结果中的报错,是变量未定义报错,那很明显是链接报错,找不到静态库
  1. 告诉编译器,库的位置。使用-L选项,后面跟库文件所在路径即可
    命令:gcc main.c -I ./lib/include -L ./lib/mymathlib 运行结果
    结果:运行失败
    结论:指定库文件路径依旧不行,因为还要指定库文件名。为什么头文件就可以不指定文件名,那是因为在main.c中已经包含了头文件名
  1. 告诉编译器库的名称。使用-l选项,后紧跟库名。注:库名称是去掉lib和.a后缀。libmymath.a:mymath就是库名
    命令:gcc main.c -I ./lib/include -L ./lib/mymathlib -lmymath
    运行结果
    运行结果:
    运行结果

②只需要带库名

方法:

  1. 把头文件和库放到系统指定路径下,就可以只带-l编译选项。其实这个动作就是库的安装
  2. 头文件和库在系统指定的目录下,建立软链接,就可以只带-l编译选项(这个下面演示一下)

演示:给头文件和库在系统指定目录下建立软链接

  1. 对头文件建立软链接 对头文件建立软链接
    • 查看系统指定目录下的软链接:建立软链接成功 软链接
    • 因为是在/usr/include目录下建立了一个路径的软链接,所以在测试使用的要包含头文件的方式要改变
      头文件包含
  • 运行程序
    命令:gcc main.c -L ./lib/mymathlib -lmymath 注意:因为头文件的软链接被放到系统的指定目录下,所以就不需要使用-I选项
    运行结果:
    运行结果
  1. 对静态库建立软链接 对静态库建立软链接
  • 运行程序
    命令:gcc main.c -I ./lib/include -lmymath 注:因为库的软链接被放到系统的指定目录下,所以就不需要使用-L选项
    运行结果:
    运行结果

注:把头文件和库在系统指定的目录下,一起建立软链接,就可以只适用-l选项。上面的演示,我没有放在一起,所以要么带L选项,要么就要带I选项

3. 小结

使用总结:

  1. 大写i(I)指定头文件所在路径
  2. 大写l(L)指定库所在路径
  3. 小写l(l)指定库名称。注:库名称是去掉lib和.a后缀

静态库总结:

  1. 把头文件和库都移动到系统的指定目录下就可以不加选项I和L,但是只要使用第三方库必定要使用gcc -l[库名](第一二方,可以理解为系统和语言层次的库)
  2. 在系统指定目录下建立软链接也可以不加选项I和L
  3. 理解库中的全局变量
  4. 如果系统只提供静态库,则编译器就只能进行静态链接
  5. 可以链接多个库

二、动态库

1. 创建动态库

创建动态库的两个关键命令

  1. 生成目标文件:gcc -fPIC -c $^
  2. 生成动态库:gcc -shared -o $@ $^

生成动态库,并且分类:
创建动态库

注:发现生成的动态库具有可执行权限 生成的动态库
虽然具有可执行权限,但是并不能执行
可执行权限:以可执行程序的方式加载到内存

2. 使用动态库

测试代码:
测试代码

  1. 编译:根据对静态库使用的编译选项,指定路径测试动态库
    命令:gcc test.c -I ./mylib/include -L ./mylib/lib -lmymethod
    编译
    结果:编译成功,生成了可执行程序a.out
  2. 运行:
    运行结果
    结果:运行失败,没有发现共享库

注:ldd命令:显示可执行程序链接的动态库

  1. 原因:
    • 因为是动态库要加载到内存。编译器确实知道了动态库的位置,但是我系统不知道——加载器
  2. 解决:
    • 拷贝到系统默认的库路径/lib64 or /usr/lib64(最常用,我们以后使用的库,都是别人成熟的库,所以可以直接安装都系统指定的目录下)
    • 在系统默认的库路径(/lib64 or /usr/lib64)下建立软链接
    • 将自己的库所在的路径,条件到系统的环境变量LD_LIBRARY_PATH中
    • /etc/ld.so.conf.d建立自己的动态库路径的配置文件,然后加载(ldconfig)

这里测试一下后面两种解决办法,前面俩种拷贝和建立软链接就不测试了

  1. 环境变量:
    解决
    • 注:重启Xshell之后,环境变量就恢复了,所以如果想一直可以,就要在配置文件中进行添加
  2. 建立自己的动态库路径的配置文件
    解决
    • 注:
      1. 添加配置文件操作需要在root账号下
      2. 进入/etc/ld.so.conf.d目录下
      3. 创建一个以.conf为后缀的文件,名字任意
      4. 文件内填入需要使用的动态库路径
      5. ldconfig更新

如果还要添加别的路径下的动态库,需要再创建文件然后写入路径

注:外部库很多,eg:ncurses库——基于终端的图形界面库(可以上网搜下载一下玩玩)

三、 动态库加载原理——进程地址空间

  1. 动态库在进程运行的时候,是要被加载的
  2. 常见的动态库被所有的可执行程序使用(eg:c标准库就被Linux很多指令共享使用)。动态库 —— 共享库

所以动态库在系统加载后,会被所以进程共享

1. 地址

①程序没有被加载前的地址

问题:程序在编译好之后,没有运行前,内部有地址吗?

通过命令,可以把编译好的程序反汇编出来
命令:objdump -S a.out
在这里插入图片描述

所以程序编译好之后,内部就有地址了,而且现在的编译器大多会采用平坦模式。这个地址就是虚拟地址,更准确的说是逻辑地址,对于目前来说,二者并没有什么区别,所以还没加载到内存,这个虚拟地址已经出现了
注:
平坦模式:内存管理模式,它将整个内存地址空间视为一个连续的线性地址空间,从0递增,程序可以直接使用线性地址进行访问

②程序加载后的地址

把可执行程序加载到内存,必然要先形成好自己的PCB
图解:
图解

2. 原理

①动态库的地址

图解:
图解

所以也得出为什么采用fPIC(产生位置无关码),因为直接用偏移量对库中的函数进行编址。而静态库就不需要这样做,因为静态库是直接拷贝到可执行程序中去的,直接编址就可以

②原理

图解:
图解

  1. 结论:虚拟地址和物理地址建立映射,从此执行任何的代码,都是在我们的进程地址空间中执行的
  2. 事实:系统在运行的时候,一定存在很多个动态库。所以OS就得管理起来 —— 先描述再组织。所以系统中所有库的加载情况,OS都清楚

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis中的单线程高性能原因和其他高级命令

单线程 Redis是单线程吗? Redis的单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的,这也是 Redis对外提供键值存储的主要流程。但Redis的其他功能,比如持久化、异步删除、 集群数据同步等,其实是由额外的线程执行的…

Spring Cloud 面试题及答案整理,最新面试题

Spring Cloud中断路器的原理及其作用是什么? Spring Cloud断路器的原理和作用基于以下几个关键点: 1、故障隔离机制: 在微服务架构中,断路器作为一种故障隔离机制,当某个服务实例出现问题时,断路器会“断…

紫光展锐携手中兴通讯成功完成业界首个5G N102芯网一体方案联调

近日,紫光展锐携手中兴通讯成功完成业界首个5G N102频段的芯网一体方案联调,包括5G NR数据呼叫、时延和峰值速率测试等用例。这是双方在5G产品和研发方面取得的重大创新成果,为推动N102频段在5G行业的应用奠定了坚实基础。 3GPP定义的N102频段…

软件测试 - 测试用例基本理论

1. 概念 为了特定的目的(该目的是检验代码是否满足用户需求)而设计的文档,文档包含测试输入、执行条件、预期结果等。文档的形式一般是excel表格。 比如说我们买了一台电脑,新买的笔记本检查完外观之后第一步需要查看电脑是否能够正常开机,…

用Python爬取古诗文网的各类古诗

fetch-gushiwen 用途 可以拿去用于个人知识库、知识图谱的创建等其他学习用途。 使用 输入古诗文网的链接,即可爬取该页面所有诗歌的诗名,作者,朝代,内容,译文,注释,赏析,创作背…

MySQL 缓存策略

MySQL 缓存方案用来干什么 ? 缓存用户定义的热点数据,用户直接从缓存中获取热点数据,降低数据的读写压力。场景分析 内存访问速度是磁盘访问速度的 10 万倍。读的需求远远大于写的需求MySQL 自身缓冲层跟业务无关。MySQL 作为项目主要数据库&#xff0…

P5076 【深基16.例7】普通二叉树(简化版)题解

题目 您需要写一种数据结构,来维护一些数(都是绝对值以内的数)的集合,最开始时集合是空的。其中需要提供以下操作,操作次数q不超过: 定义数x的排名为集合中小于x的数的个数1。查询数x的排名。注意x不一定…

【ICM】好奇心机制

文章目录 样本经验处理降低图片像素和通道构建连续状态捕捉动作经验回放类 各部分的模型编码器模型反向模型正向模型DQN模型ICM 的 反向传播 概念补充强化学习组成元素按照学习目标来分按照策略更新方式区分强化学习on-line 与 off-line经验回放 全部代码 样本经验处理 降低图…

什么是物联网?物联网如何工作?

物联网到底是什么? 物联网(Internet of Things,IoT)的概念最早于1999年被提出,官方解释为“万物相连的互联网”,是在互联网基础上延伸和扩展,将各种信息传感设备与网络结合起来而形成的一个巨大网络,可以实…

无法启动报,To install it, you can run: npm install --save @/components/iFrame/index

运行的过程中后台报错 npm install --save /components/iFrame/index,以为是安装三方依赖错误,经过多次重装node_modules依然没有用。 没办法,只能在项目中搜索 components/iFrame/index这个文件。。突然醒悟。。。 有时候,犯迷…

MySQL面试题【全面】2024

基础内容 1、MySQL的架构分层 (1)Serve层:负责建立连接、分析和执行 SQL。 MySQL 大多数的核心功能模块都在这实现,主要包括连接器,查询缓存、解析器、预处理器、优化器、执行器等。另外,所有的内置函数&…

详解C#之WinForm版利用RichTextBox 制作文本编辑器【附源码】

在Windows应用程序开发中,刚刚介绍了WPF版的利用RichTextBox实现文本编辑器,今天继续推出WinForm版的利用RichTextBox实现文本编辑器。本文利用一个简单的小例子,简述如何在WinForm开发中,利用RichTextBox开发文本编辑器&#xff…

Spring中@import注解终极揭秘!

技术概念 它能干啥 Import注解在Spring框架中主要用于解决模块化和配置管理方面的技术问题,它可以帮助开发者实现以下几个目标: 模块化配置:在大型项目中,通常需要将配置信息分散到多个配置类中,以便更好地组织和管…

C++面试干货---带你梳理常考的面试题(二)

顾得泉:个人主页 个人专栏:《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂,年薪百万! 1.struct 和 class 区别 1.默认访问权限:struct中的成员默认为public,而class中的成员默认为priv…

力扣404 左叶子之和 Java版本

文章目录 题目描述解题思路代码 题目描述 给定二叉树的根节点 root ,返回所有左叶子之和。 示例 1: 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 2…

二手手机管理系统|基于Springboot的二手手机管理系统设计与实现(源码+数据库+文档)

二手手机管理系统目录 目录 基于Springboot的二手手机管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、用户管理功能的实现界面 2、用户中心管理功能的实现界面 3、新闻信息管理功能的实现界面 4、商品收藏管理功能的实现界面 5、订单管理功能的实现界…

2024年3月6日 十二生肖 今日运势

小运播报:2024年3月6日,星期三,农历正月廿六 (甲辰年丁卯月己巳日),法定工作日。 红榜生肖:牛、猴、鸡 需要注意:鼠、虎、猪 喜神方位:东北方 财神方位:正…

【pyinstaller打包记录】Windows系统打包exe后,onnxruntime报警告(Init provider bridge failed)

简介 PyInstaller 是一个用于将 Python 程序打包成可执行文件(可执行程序)的工具。它能够将 Python 代码和其相关的依赖项(包括 Python 解释器、依赖的模块、库文件等)打包成一个独立的可执行文件,方便在不同环境中运行…

【Java设计模式】五、建造者模式

文章目录 1、建造者模式2、案例:共享单车的创建3、其他用途 1、建造者模式 某个对象的构建复杂将复杂的对象的创建 和 属性赋值所分离,使得同样的构建过程可以创建不同的表示建造的过程和细节调用者不需要知道,只需要通过构建者去进行操作 …

【SpringBoot3.x教程 01】SpringBoot简介及工程搭建

前言:什么是SpringBoot? SpringBoot是一个开源的Java基础框架,它被设计来简化Spring应用的初始搭建以及开发过程。这个框架利用了“约定优于配置”的理念,提供了一系列大型项目中常用的默认配置,让开发者可以快速启动和…