【Linux】动静态库

devtools/2025/2/25 3:22:25/

目录

站在库提供者的角度

静态库

制作静态库

静态库的内容

发布静态库

用户使用静态库

找头文件

找库文件

动态库

制作动态库

动态库报错 

动态库是怎么被加载的?

地址相关问题

程序加载前的地址

程序加载后的地址

如何执行第一条指令?

动态库的地址


站在库提供者的角度

有两种方法


静态库

制作静态库

ar是一个生成静态库的命令,目的是把所有.o文件打包成一个.a文件。

rc是表示在.a文件中创建或替换.o文件。


静态库的内容

把源文件变成.o文件然后打包成一个库,这就是静态库。


发布静态库

当别人需要使用我们的静态库时,只用把lib给他就行了。


用户使用静态库

找头文件

gcc编译时,会去系统默认头文件目录和当前目录找对应头文件,加一个I后面跟指定目录就是告诉系统顺便去这里找一下头文件。

找库文件

gcc编译时,会去系统默认库路径下找库文件,加L后面跟路径就是告诉系统来这个路径找库文件,加l后面直接跟库的名字就是告诉系统我要链接这个库。

总结:第一步找头文件,第二步找库文件,第三步指定哪个库。

如果不想这么麻烦,我们可以把头文件和库文件放到系统默认路径中,或者在系统默认路径建立软链接。

放到默认路径相当于安装。

在系统默认路径下添加一个软链接。


动态库

在链接之前,动静态库都一样,都需要把源文件变成.o文件。

制作动态库

先准备一些源文件和头文件。

一次生成两个库。

生成静态库。

生成动态库。

把源文件编译成.o文件时要加fPIC,把.o文件打包成库时要加shared。

清理和发布,生成一个目录进行存放。

发布形成自己的库。

这个库给别人使用。

main.c要包头文件。

使用静态库。

使用动态库。

同时依赖多个库。


 

动态库报错 

关于动态库的报错。

已经告诉了你在哪里,为什么会找不到?

原因在于你告诉的是编译器,编译完后变成可执行程序就和编译器没关系了。

这里报的是加载错误,就是你还得告诉系统,告诉加载器,不仅编译要有路径,加载也要有路径。

一个有四种做法,

第一:直接把库拷贝(安装)到系统路径中。

第二:在系统路径建立软链接。

第三:添加环境变量,这个环境变量是用来搜索用户自定义库的路径。 

把动态库所在的路径添加到环境变量中。

第四:设置配置文件。

进入这个目录,这里面存放的都是配置文件。

创建一个配置文件,把动态库的路径写进去。

重新加载配置文件。

环境变量是临时的,配置文件是永久的。


动态库是怎么被加载的?

动态库也是文件,先从磁盘加载到物理内存中,进程的页表会把动态库的位置和自己的共享区建立映射。

当进程要用到动态库时,会判断是否已经加载,如果已经加载了,那么页表直接映射到自己的共享区即可。

库里面的全局数据会不会因为多进程而受到影响?

不会,会发生写时拷贝。


地址相关问题

程序加载前的地址

程序编译之后,内部就具备地址。

平坦模式:程序内部的地址编排和虚拟地址基本一致。(编译器要考虑操作系统)

当程序在磁盘中还未加载时就已经具备了地址,这个地址叫逻辑地址,相当于虚拟地址,也就是在磁盘中还未加载时就已经照顾到虚拟地址了。


objdump -S 将程序反汇编。

程序加载后的地址

程序加载到物理内存后也会自动有对应的物理地址。

如何执行第一条指令?

进程会记录自己在哪个工作目录下,进程也能找到自己的可执行程序。

第一步,读取可执行程序,CPU的pc寄存器会获取对应的入口地址。这个入口地址是程序加载前就有的,是逻辑地址所以相当于虚拟地址。

第二步,用虚拟地址去页表找物理地址,但此时并没有建立映射,此时会触发缺页中断,然后加载程序,建立映射。

第三步,系统知道指令的长度,每读完一条指令,PC存的地址就往后加,就这样不断向后执行。

如果读到call指令,CPU会发现这是函数调用,CPU读到的指令内部可能有地址,这个地址是逻辑地址,也就是虚拟地址,所以就直接用虚拟地址去找物理地址。物理地址不存在就缺页中断加载程序默认就有对应的物理地址了,然后建立映射。


动态库的地址

程序用到库函数,触发缺页中断库会加载,库的虚拟地址和物理地址建立映射,虚拟地址在共享区。

库的地址不能是固定的,只能是任意位置加载。

库内部函数的地址是偏移量。

加载库的地址是库的起始地址,当用到库函数时就用起始地址加偏移量找到对应虚拟地址然后找到映射。

保证库可以在虚拟内存任意位置加载。


 

因为静态库会直接拷贝到可执行程序里。静态库编译的时候就是按虚拟地址编的,位置是确定的。


http://www.ppmy.cn/devtools/161485.html

相关文章

认知重构 | 自我分化 | 苏格拉底式提问

注:本文为 “认知重构 | 自我分化” 相关文章合辑。 心理学上有一个词叫:认知重构(改变 “非黑即白,一分为二” 的思维方式) 原创 心理师威叔 心理自救 2024 年 10 月 26 日 19:08 广东 你有没有过这样的时候&#x…

uniapp 网络请求封装(uni.request 与 uView-Plus)

一、背景 在开发项目中,需要经常与后端服务器进行交互;为了提高开发效率和代码维护性,以及降低重复性代码,便对网络请求进行封装统一管理。 二、创建环境文件 2.1、根目录新建utils文件夹,utils文件夹内新建env.js文…

【Python爬虫(58)】从0到1:Scrapy实战爬取大型新闻网站

【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取&#xff…

python制图之小提琴图

提琴图(Violin Plot)是一种结合了箱线图(Box Plot)和核密度估计(Kernel Density Estimation, KDE)的可视化工具,用于展示数据的分布情况和概率密度。它在数据可视化中具有独特的作用.本节我们学…

可编辑35页PPT | DeepSeek如何赋能职场应用

DeepSeek作为一款基于人工智能技术的多模态AI工具,近年来在职场应用中迅速崭露头角,以其强大的功能和高效的表现赢得了广泛的赞誉。DeepSeek融合了文本生成、图像创作、数据分析与可视化等多种功能,为职场人士提供了前所未有的便利和效率提升…

C#初级教程(4)——流程控制:从基础到实践

1.为什么需要流程控制 有时候,需要根据程序运行时的具体环境,有选择地执行不同代码段;而有时候,则需要反复执行同一段代码。这时候,流程控制中的分支和循环就发挥了关键作用。分支能让代码根据条件判断结果来决定执行路…

Java List 自定义对象排序 Java 8 及以上版本使用 Stream API

从 Java 8 开始,你可以使用 Stream API 对 List 进行排序,这种方式更加简洁和灵活。 以下是一个示例代码: import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors;// 自定…

基于Java的实时数据流处理框架设计与实现

基于Java的实时数据流处理框架设计与实现 在大数据时代,实时数据流处理成为了数据分析与处理的重要组成部分。尤其是在需要快速响应的场景中,数据流处理显得尤为关键。本文将详细介绍如何设计与实现一个基于Java的实时数据流处理框架,并通过…