Linux的库文件

概述:

库文件一般就是编译好的二进制文件,用于在链接阶段同目标代码一块生成可执行文件,或者运行可执行文件的时候被加载,以遍调用库文件中的某段代码。

动态链接都是索引的.so文件,静态链接都是压缩打包的.a文件。

库文件和可执行文件相比:

  • 相同点:两者都是编译好的二进制文件
  • 不同点:库文件没法直接执行(直观上看,他的源代码中没有main函数,而只是一些函数模块的定义和实现,没有运行的入口主函数,所以库文件没法直接执行)。

我们的程序开发,无论是运行的时候,还是编译,链接的时候,一般都需要借助一些库来实现他们的功能,而很少直接通过程序的源代码生成完全独立的可执行文件。

静态库:

静态库概述:

        静态库实际上就是一些目标文件的(一般是以.o结尾)的集合,静态库一般是以.a结尾,只用于链接生成可执行文件阶段。

具体来说,以c程序为例子,一般我们编译程序源代码的时候过程大致是:

  • 以.c为后缀的源文件经过编译生成.o文件的目标文件
  • 以.o为后缀的目标文件经过链接生成最终的可执行文件。

我们可以在链接的时候直接链接.o的目标文件,也可以将这些.o文件打包集中起来,统一链接,而生成的打包集成了所有.o文件,也就是静态库。

        静态库只在程序连接的时候时候,连接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中,一旦链接完成生成可执行文件之后,执行程序的时候就不再需要静态库了

        由于每一个静态库的应用程序都是需要拷贝所用到的函数的代码,所以静态库链接生成可执行文件会比较大,多个程序运行的时候占用的内存空间比较大,(每个程序在内存中都有一份复制的静态库代码),但是由于运行的时候不用从外部动态加载额外的库了,速度会比共享库快。

静态库的制作

实例:假设在实际工作中设计了两个算法,但是需要卖给其他公司使用,为了保护公司的知识产权是不能将源代码交给其他公司的,这样我们可以将两个算法封装或者打包到一个静态库中。

假设实现这两个算法的函数为func1()和func()2。

新建一个头文件hello.h,在hello.h中对两个函数进行声明:

编写一个简单的程序“hello.c”

将hello.c编译生成.o文件

gcc -c hello.c -o hello.o

使用ar命令(ar是archive的意思)将hello.o文件打包成一个静态库文件libhello.a

 ar rcs libhello.a hello.o

注意:

  1. 如果需要将多个.o文件打包成文件库,则在命令行后边填写所有.o文件的名字即可
  2. 生成的库的名字必须是libxxx.a格式(注意:这里是尽量最好使用lib开头的格式,因为其他格式的编译方式是不一样的)

编译参数:<rcs>

r:表明将模块加入到静态库中,c表示创建静态库,s表示产生索引

使用nm命令查看库文件中包含的符号:nm libhello.a

使用 ar -t 命令查看静态库是由那些.o文件组成的:ar -t libhello.a

编写一个带有主函数的程序main.c,并且在main.c中调用静态库中的func1和func2函数:

现在所有文件下都在同一个目录下,没法直接体现出来静态库的作用。

在IO_file_test目录下新建一个static_lib_test目录进行测试将文件移动到下边设备树结构。(这里是一个比较常用的目录结构,但是为了方便测试三个文件都放在一个文件目录下即可)

解释:

include目录下是.h文件

lib里边是链接的静态库文件

src里边是.c文件

编译:

gcc main.c -L../lib -lhello -I../include -o main

编译解释:

-L指向的是链接的静态库路径

-l(小L)是静态库的命称(去掉lib之后的)

-I(大i)链接存放.h文件的路径

编译现象:

在静态库的概述中会标红的地方提到了(一旦链接完成生成可执行文件之后,执行程序的时候就不再需要静态库了),所以这时删除掉libhello.a文件后程序仍然可以执行。

共享库(动态库)

共享库概述

共享库也叫做动态库

静态库缺点:

  1. 内存消耗大;(假设一个静态库的大小为1M,当两千个程序都用到这库将消耗掉2G内存)
  2. 当静态库中的代码优化的时候,所有调用该静态库的程序需要重新编译,这样太过与麻烦。

动态库特点:

  1. 动态库在程序编译的时候并不会被链接到目标代码当中,而是在程序运行的时候才被载入。
  2. 不同的应用程序如果调用相同的库,那么在内存中里只需要有一份共享库的实例,规避了空间浪费问题。
  3. 动态库在程序运行的时候才能被载入,也解决了静态库对程序的更新,部署和发布页带来的麻烦。用户只需要更新动态库即可,增量更新。

动态库制作

参照静态库目录下创建三个文件如下:内容和静态库的也相同

编译链接生成.o文件

将编译好生成好的hello.o编译编译生成动态库:gcc -shared -fPIC -o libhello.so hello.o

注意:

  1. -shared:表明是使用的共享库
  2. -fPIC:表明生成与位置无关的代码、
  3. 动态库后缀为.so
  4. 动态库格式libxxx.so
  5. 如果还有其他链接的.o文件,直接在hello.o后边加上,用空格隔开

使用nm命令查看一个库文件中包含的符号: nm libhello.so

对照静态库测试目录制作动态库目录格式:

将上边共享库目录的文件对应拷贝到共享库测试目录里边如下:

进行编译:gcc main.c -L../lib -lhello -I../include -o main

但是如果直接执行的话,编译器会爆出一个错误。

错误的主要意思是在加载的时候打不开动态库文件,但是注意:动态库在在程序执行的时候会被加载。

这是因为在Linux中启动一个ELF格式的二进制可执行文件会自动启动和运行一个program loader(程序加载器:用来加载一些库)。对于Linux系统,这个loader的名字是ld-linux.so.X(X是版本号)。这个loader启动后会load所有的其他本程序的要使用的共享函数库。动态库与静态库不同,在执行文件的阶段需要加载动态库文件,而加载的动态库文件需要在指定位置或者添加在环境变量中,才能正确的加载动态库文件。

动态链接库的查找先后顺序:

  • LD_LIBRARY_PATH环境变量中的路径
  • /etc/ld.so.cache缓存文件
  • /usr/lib和/lib

动态库临时生效

可以临时将libhello.so所在的路径追加到环境变量LD_LIBRARY_PATH中

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/IO_file_test/shared_lib_test/lib

冒号后边跟是自己的动态库路径。

修改完成之后我们可以使用echo $LD_LIBRARY_PATH查看环境变量被修改的值

注意: 在终端使用expert命令来修改当前环境变量的值,只是对当前会话临时生效,如果切换到一个新的会话窗口或者新的终端,关闭当前会话窗口都会失效。

动态库长期生效

  • 修改系统启动配置文件,将export命令添加到启动文件当中

设置环境变量:
      1.打开 vim ~/.bashrc 文件
       2.在文件末尾添加一行
            export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径(如果需要删除环境变量,需要在~/.bashrc中删除环境变量后,关掉终端,重新启动终端才能生效)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/IO_file_test/shared_lib_test/lib
       3.重新加载配置文件 source ~/.bashrc

  • 将动态库文件拷贝到/usr/lib或者/lib目录下(一般不采用这个种方式,因为这样会污染系统,并且不方便项目迁移)
  • 修改/etc/ld.so.conf文件

动态库的升级

引入:

在实际工作当中,我们可能经常需要对动态库的板本进行升级,假如原来的库为libhello.so,那么升级完以后还需要保留每一个旧的板本,动态库的名字就不能重复,但是程序在加载的时候只加载libhello.so文件,解决:所以我们可以对每一个板本的动态库文件进行不同的命名,然后在新建立软链接,链接需要使用的实体库即可。

根据动态的命名规则,我们可以将动态库的第一个板本命名为:libhello.so.1.0.0,然后创建软连接

ln -s libhello.so.1.0.0 libhello.so

假设我们在原来的库上增加了某些接口我们可以将新库的版本名命名为libhello.so.1.1.0,删除原来的软连接文件,并重新创建软链接文件到该文件。

位置无关代码

        位置无关代码(PIC:position-independent code),也被称为地址无关代码,是指源代码被编译成二进制文件(可以是执行文件也可以是某个库文件),编码方式也和位置(地址)无关。

        程序在运行的时候是需要被加载到物理内存上运行的,但是操作系统为了方便每个进程进行内存管理,使用虚拟内存技术,每一个进程运行时都会得到4G的虚拟内存。这个虚拟内存可以认为每个进程任务自己认为自己有4G的空间,着只是每个进程认为的,但是实际上,在虚拟内存对应的物理内存上,可能只对应一点点的物理内存,实际用了多少内存,就会对应多少物理内存。

使用静态库和动态库编译生成的可执行文件在运行时候在内存上的加载方式:

如果使用了静态库编译可执行程序,每个函数在内存中的位置(地址)在编译完成以后就已经决定了。

但是共享库(动态库)是在可执行程序执行的时候加载进去的,动态编译后的函数的调用地址是自动计算出来的,这就是与位置无关的代码。

下边是找到的一个资料对位置无关代码的验证:

在64为机器上可以运行32位的指令。

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

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

相关文章

Python新春烟花盛宴

写在前面 哈喽小伙伴们&#xff0c;博主在这里提前祝大家新春快乐呀&#xff01;我用Python绽放了一场新春烟花盛宴&#xff0c;一起来看看吧&#xff01; 环境需求 python3.11.4及以上PyCharm Community Edition 2023.2.5pyinstaller6.2.0&#xff08;可选&#xff0c;这个库…

React实例之完善布局菜单(三)

接着上篇的内容继续。规划界面布局。界面分为三个部分&#xff0c;左边为菜单部分&#xff0c;右边上部有个 80 px 高度左右的功能区&#xff0c;下面是主内容区。 依据这个设计&#xff0c;我们进行下面的步骤&#xff1a; 在 SMenu项目中创建一个目录&#xff1a; SLayout, …

C++实战Opencv第二天——色彩空间转换函数和opencv中图像对象创建与赋值(从零开始,保姆教学)

OpenCV是一个强大的计算机视觉库&#xff0c;使用C作为主要编程语言&#xff0c;对于图像处理和计算机视觉领域具有重要意义。其提供了丰富的功能和算法&#xff0c;使得开发者能够快速实现各种图像处理和计算机视觉应用。OpenCV C为图像处理和计算机视觉领域的开发者提供了一个…

【实战】阿里智能编码助手通义灵码

文章目录 前言技术积累通义灵码是什么&#xff1f;Copilot是什么&#xff1f;通义灵码主要功能通义灵码有哪些优势&#xff1f;通义灵码支持语言/工具通义灵码接入方式通义灵码帮助中心 实战演示安装插件行/函数级实时续写自然语言生成代码代码优化单元测试生成代码注释生成解释…

【RPA】什么是RPA

一、什么是RPA? RPA&#xff0c;全称机器人流程自动化&#xff0c;是一种利用机器人技术实现工作信息与业务交互自动化的过程。它能够按照预先设计的流程&#xff0c;高效地处理大量的工作信息与业务交互&#xff0c;极大地节约了人工成本。如今&#xff0c;RPA已成为智能化软…

贪心算法篇

“靠漫步&#xff0c;将生趣填饱~” 贪心算法简介&#xff1f; 贪心算法&#xff08;Greedy Algorithm&#xff09;&#xff0c;也称为贪婪算法&#xff0c;是一种在解决问题时采取贪心策略的方法。其基本原理是很简单的&#xff1a; “在每个决策点上都选择当下看似最好的选项…

《动手学深度学习(PyTorch版)》笔记7.1

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…

FANUC机器人PROF-017从机断开故障报警处理方法总结

FANUC机器人PROF-017从机断开故障报警处理方法总结 情况说明&#xff1a; 机器人安装的是PROFINET板卡&#xff0c;按照手册进行PROFINET配置之后&#xff0c;重启控制柜&#xff0c;此时系统提示&#xff1a;PROF-017 从机断开&#xff0c; 如下图所示&#xff0c; 打电话咨…

HTML5和CSS3强化知识总结

HTML5的新特性 HTML5的新增特性主要是针对于以前的不足&#xff0c;增一些新的标签、新的表单和新的表单属性等。这些新特性都有兼容性问题&#xff0c;基本是IE9以上版本的浏览器才支持&#xff0c;如果不考虑兼容性问题&#xff0c;可以大量使用这些新特性。 HTML5新增的语义…

ubuntu 18.04修改网卡名称

1.原来网卡配置 现在要把enp3s0的名称改为eth0 2. 总共修改三个文件 第一个修改 sudo vi /etc/default/grub 添加最后一行 GRUB_CMDLINE_LINUX"net.ifnames0 biosdevname0" 第二个修改sudo vi /etc/udev/rules.d/70-persistent-net.rules 如果没有就新建文件&a…

uniapp android和微信小程序实现PDF在线预览

在使用uniapp开发移动端时&#xff0c;微信开发者工具里webview能正常打开后端接口返回的pdf文件流。正式发布后&#xff0c;在配置了业务域名和服务器域名的前提下&#xff0c;预览pdf文件却只能看到白屏&#xff0c;因此我猜测微信小程序不能通过webview读取文件流。这个想法…

python接口自动化(五)--接口测试用例和接口测试报告模板(详解)

简介 当今社会在测试领域&#xff0c;接口测试已经越来越多的被提及&#xff0c;被重视&#xff0c;而且现在好多招聘信息要对接口测试提出要求。区别于传统意义上的系统级别测试&#xff0c;很多测试人员在接触到接口测试的时候&#xff0c;也许对测试执行还可以比较顺利的上手…

C2-Search-Netlas:一款基于Netlas API的强大C2服务器识别与检测工具

关于C2-Search-Netlas C2-Search-Netlas是一款功能强大的命令与控制&#xff08;C2&#xff09;服务器检测工具&#xff0c;该工具使用Java语言开发&#xff0c;基于Netlas API实现其功能&#xff0c;可以帮助广大研究人员轻松快速地识别和检测目标C2服务器的相关信息。 C2-S…

Redis之基础篇

Redis简介 Redis是一种基于键值对&#xff08;Key-Value&#xff09;的NoSQL数据库&#xff0c;它支持string&#xff08;字符串&#xff09;、hash&#xff08;哈希&#xff09;、list&#xff08;列表&#xff09;、set&#xff08;集合&#xff09;、zset&#xff08;有序集…

随机图论基础

一&#xff0c;随机图、随机图空间 1&#xff0c;随机图 一个n个点的无向图&#xff0c;最多有sn(n-1)/2条边。 每条边都有一定的概率存在&#xff0c;有一定概率不存在&#xff0c;那么每个图都有一个出现概率。 2&#xff0c;随机图空间 一共有2^s种不同的图&#xff0c…

[word] word怎么让字在横线上居中 #学习方法#媒体#媒体

word怎么让字在横线上居中 word怎么让字在横线上居中&#xff1f; 在word文档中&#xff0c;有时为了某些字句突出显示&#xff0c;需要用下划线来表示&#xff0c;当着重显示部分为金额、面积或某些选项时&#xff0c;需要一条长下划线上左右有空白&#xff0c;而文字在下划…

【vscode】windows11在vscode终端控制台中打印console.log()出现中文乱码问题解决

1. 问题描述 在前端开发过程中使用vscode编写node.js&#xff0c;需要在控制台中打印一些中文信息&#xff0c;但是一直出现中文乱码问题&#xff0c;英文和数字都显示正常。在网上试了很多设置的办法&#xff0c;最终找到windos11设置中解决。 2. 原因 首先打开控制台&…

centos 7.7 离线安装docker

centos 7.7 离线安装docker Index of linux/static/stable/x86_64/https://download.docker.com/linux/static/stable/x86_64/ 【1】离线下载docker 压缩包上传至 /usr/local 目录&#xff0c;解压缩&#xff0c;并复制到 /usr/bin/ 目录中。 cd /usr/local/tar -zxvf docke…

力扣 第 123 场双周赛 解题报告 | 珂学家 | 二维偏序+单调队列优化

前言 执手看歌敲金钗&#xff0c;笑语落珠明眸睐。 忽然蝴蝶春风满&#xff0c;焉教冷镜瘦朱颜。 整体评价 T3是基于map的前缀和的变形题&#xff0c;T4是二维偏序的一道应用题。 题外话&#xff0c;力扣还是实现N久之前的承诺了&#xff0c;命名权奖励&#xff0c;赞一个。 …

7隐藏进程_Linux_Rootkit.md

Xcellerator 密码学Linux其他逆向工程 文章目录 [Linux Rootkit 第 7 部分&#xff1a;隐藏进程](https://xcellerator.github.io/posts/linux_rootkits_07/)选择要隐藏的 PID隐藏 PID Linux Rootkit 第 7 部分&#xff1a;隐藏进程 2020-10-01 :: TheXcellerator # linux #…