我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Linux静态库与动态库如何制作

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Linux静态库与动态库如何制作

这篇“Linux静态库与动态库如何制作”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Linux静态库与动态库如何制作”文章吧。

静态库就是在编译过程中一些目标文件的集合。静态库在程序链接的时候使用,链接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中。

相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,而只是作些标记。然后在程序开始启动运行的时候,动态地加载所需模块,因此动态函数库所产生的可执行文件比较小。

Linux系统中:

静态库的扩展名为.a; 2.动态库的扩展名为.so;

源代码到可执行程序的转换时需要经历如下图所示的过程:

Linux静态库与动态库如何制作

编译是指把用高级语言编写的程序转换成相应处理器的汇编语言程序的过程。 2.汇编是从汇编语言程序生成目标系统的二进制代码(机器代码)的过程。 3.链接是指将汇编生成的多段机器代码组合成一个可执行程序。

通过编译和汇编过程,每一个源文件将生成一个目标文件。连接器的作用就是将这些目标文件组合起来,组合的过程包括了代码段、数据段等部分的合并,以及添加相应的文件头。

最后得到的可执行文件如何作用的:

  Linux静态库与动态库如何制作

ELF文件格式包括三种主要的类型:可执行文件、可重定向文件、共享库。

1.可执行文件(应用程序)

可执行文件包含了代码和数据,是可以直接运行的程序。

2.可重定向文件(*.o)

可重定向文件又称为目标文件,它包含了代码和数据(这些数据是和其他重定位文件和共享的object文件一起连接时使用的)。

.o文件参与程序的连接(创建一个程序)和程序的执行(运行一个程序),它提供了一个方便有效的方法来用并行的视角看待文件的内容,这些.o文件的活动可以反映出不同的需要。

Linux下,我们可以用gcc -c编译源文件时可将其编译成*.o格式。

3.共享文件(*.so)

也称为动态库文件,它包含了代码和数据(这些数据是在连接时候被连接器ld和运行时动态连接器使用的)。动态连接器可能称为ld.so.1,libc.so.1或者 ld-linux.so.1。我的CentOS6.0系统中该文件为:/lib/ld-2.12.so

库是一种可执行代码的二进制格式,能够被载入到内存中执行,库分静态库和动态库两种:

静态库:这类库的名字一般是libxxx.a,xxx为库的名字。利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。

动态库:这类库的名字一般是libxxx.M.N.so,同样的xxx为库的名字,M是库的主版本号,N是库的副版本号。当然也可以不要版本号,但名字必须有。相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib。

当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

制作静态链接库:

准备两个源码文件st1.cpp和st2.cpp,用它们来制作库libmytest.a

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ cat st1.cpp#include using namespace std;void display1(){   cout"This is my first static library!!!"#include using namespace std;void display2(){   cout"This is my second static library"

把两个源码文件生成目标文件

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ g++ -c st1.cpp  st2.cppxzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll总用量 24drwxrwxr-x 2 xzj xzj 4096 7月  16 15:39 ./drwxrwxr-x 7 xzj xzj 4096 7月  16 15:26 ../-rw-rw-r-- 1 xzj xzj  115 7月  16 15:35 st1.cpp-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st1.o-rw-rw-r-- 1 xzj xzj  113 7月  16 15:35 st2.cpp-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st2.o

使用ar -rsv libmytest.a st1.o st2.o制作静态库

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ar -rsv libmytest.a st1.o st2.oar: 正在创建 libmytest.aa - st1.oa - st2.oxzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll总用量 32drwxrwxr-x 2 xzj xzj 4096 7月  16 15:42 ./drwxrwxr-x 7 xzj xzj 4096 7月  16 15:26 ../-rw-rw-r-- 1 xzj xzj 5586 7月  16 15:42 libmytest.a-rw-rw-r-- 1 xzj xzj  115 7月  16 15:35 st1.cpp-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st1.o-rw-rw-r-- 1 xzj xzj  113 7月  16 15:35 st2.cpp-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st2.o用file命令查看其属性,发现它确实是归档压缩文件xzj@xzj-VirtualBox:~/development_test/static_lib_test$ file libmytest.alibmytest.a: current ar archive用ar -t libmytest.a可以查看一个静态库包含了那些obj文件:xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ar -t libmytest.ast1.ost2.o

写个测试程序来调用库libmytest.a中所提供的两个接口display1()和display2()。

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ cat main.cppvoid display1();void display2();int main(){   display1();   display2();   return 0;}xzj@xzj-VirtualBox:~/development_test/static_lib_test$ g++ -o run main.cpp  -L./  -lmytestxzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll总用量 48drwxrwxr-x 2 xzj xzj 4096 7月  16 15:54 ./drwxrwxr-x 7 xzj xzj 4096 7月  16 15:26 ../-rw-rw-r-- 1 xzj xzj 5586 7月  16 15:42 libmytest.a-rw-rw-r-- 1 xzj xzj   95 7月  16 15:53 main.cpp-rwxrwxr-x 1 xzj xzj 9424 7月  16 15:54 run*-rw-rw-r-- 1 xzj xzj  115 7月  16 15:35 st1.cpp-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st1.o-rw-rw-r-- 1 xzj xzj  113 7月  16 15:35 st2.cpp-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st2.o结果调用成功:xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ./runThis is my first static library!!!This is my second static library

制作动态库

静态库*.a文件的存在主要是为了支持较老的a.out格式的可执行文件而存在的。目前用的最多的要数动态库了。

动态库的后缀为*.so。在Linux发行版中大多数的动态库基本都位于/usr/lib和/lib目录下。在开发和使用我们自己动态库之前,请容许我先落里罗嗦的跟大家唠叨唠叨Linux下和动态库相关的事儿吧。

有时候当我们的应用程序无法运行时,它会提示我们说它找不到什么样的库,或者哪个库的版本又不合它胃口了等等之类的话。那么应用程序它是怎么知道需要哪些库的呢?我们前面已几个学了个很棒的命令ldd,用就是用来查看一个文件到底依赖了那些so库文件。

Linux系统中动态链接库的配置文件一般在/etc/ld.so.conf文件内,它里面存放的内容是可以被Linux共享的动态联库所在的目录的名字。我的系统中,该文件的内容如下:

xzj@xzj-VirtualBox:/etc$ cat /etc/ld.so.confinclude /etc/ld.so.conf.d

add=dlsym(”xxx.so”,”add”);

add(89,369); 代码搞起

#include "my_so_test.h"#include #include #include extern "C"{   void (*fn)(void);}int main(int argc, char const *argv[]){void *handle = dlopen("./libtest.so",RTLD_LAZY);if (NULL != handle) {  printf("nihao\n");}fn = (void (*)(void))dlsym(handle,"test_hubei");fn();dlclose(handle);return 0;}

执行结果:

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ test_hubei.cpp  test_wuhan.cpp test_xiaogan.cpp -fPIC  -shared -o libtest.soxzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ -o mmain_run mmain.cpp  -rdynamic -ldlxzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ./mmain_runnihao欢迎来到湖北!欢迎来到武汉!!欢迎来到孝感!

每次修改源文件,一定要重新生成动态文件.so,否则一直在用之前生产的文件。不利于调式出现的错误!

编译参数

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

-L.:表示要连接的库在当前目录中

-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。

注意的问题

调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。

在生成动态库时的参数-fPIC

-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code), 则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意 位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

gcc -shared -fPIC -o 1.so 1.c 这里有一个-fPIC参数 PIC就是position independent code PIC使.so文件的代码段变为真正意义上的共享 如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy.每个copy都不一样,取决于 这个.so文件代码段和数据段内存映射的位置.

不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码) 如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了.(因为so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享) 我们总是用fPIC来生成so,也从来不用fPIC来生成a. fPIC与动态链接可以说基本没有关系,libc.so一样可以不用fPIC编译,只是这样的so必须要在加载到用户程序的地址空间时重定向所有表目.

PIC原理与意义

载入时重定位的缺点:

(1)动态库的代码段不能在进程间共享:多个进程加载同一个动态库到各自不同的地址空间,导致代码段需要不同的重定位,所以最终每个引用该动态库的进程拥有一份该动态库代码段的不同拷贝。(2)代码段必须是可写的,增加了被攻击风险。为了解决载入时重定位的问题,引入了PIC的概念,即位置无关代码。PIC实现原理:(1)GOT:在动态库的数据段增加GOT(Global Offset Table),该表的每一项是符号到地址的绝对映射。由于代码段到数据段的偏移是固定的,因此可以在编译时确定代码段中的某个符号到GOT特定项之间的偏移。这样,代码段中的符号偏移就可以在编译时确定了,在加载时也无需修改代码段的内容,只需要填写位于数据段的GOT的所有项的符号的绝对地址就完成了。因为数据段本来就是进程间不共享,每个进程独立的一份,因此GOT的设计完全解决了以上两个问题,从而达到两个目的:1,代码段可以在多进程间共享;2,代码段是只读的。(2)PLT:PLT是 Program Linkage Table 的缩写,即程序链接表,PLT的出现是为了延时定位的目的。一个动态库中的函数往往要远多于全局变量,并且被调用的函数往往少于定义的函数。GOT中包含了该动态库中的所有的全局变量的映射,并且在连接器加载时解析所有的全局变量的地址。如果用同样的方式去处理函数调用符号,则开销会非常大。因此在代码段设计了一个PLT表,每一项其实是个代码段,用于执行如下逻辑:首次访问时,解析参数和向GOT填写函数地址,后续访问直接访问GOT中的函数地址。如此达到了延时定位的目的。因此,一个PIC的动态库中,对全局变量使用GOT来映射,对函数调用使用PLT+GOT来映射,从而达到共享库代码段复用,代码段安全访问的目的。而这些就是 PIC 的意义。

以上就是关于“Linux静态库与动态库如何制作”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Linux静态库与动态库如何制作

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Linux静态库与动态库如何制作

这篇“Linux静态库与动态库如何制作”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Linux静态库与动态库如何制作”文章吧
2023-06-27

如何在 Linux 中使用动态和静态库

本篇内容介绍了“如何在 Linux 中使用动态和静态库”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!了解 Linux 如何使用库,包括静态库
2023-06-15

linux静态库和动态库的创建与使用方法

这篇文章主要介绍“linux静态库和动态库的创建与使用方法”,在日常操作中,相信很多人在linux静态库和动态库的创建与使用方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”linux静态库和动态库的创建与使
2023-06-13

Linux动态库和静态库的示例分析

今天就跟大家聊聊有关Linux动态库和静态库的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。函数库分为静态库和动态库两种。创建Linux静态库和Linux动态库和使用它们在这
2023-06-16

linux中怎么生成动态库和静态库

linux中怎么生成动态库和静态库,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。动态库的生成:1、代码如下:#include #in
2023-06-09

linux中动态库和静态库的区别有哪些

这篇文章将为大家详细讲解有关linux中动态库和静态库的区别有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。区别:1、静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库;动态库在程序
2023-06-25

Linux静态函数库和动态函数库是什么

这篇文章主要介绍“Linux静态函数库和动态函数库是什么”,在日常操作中,相信很多人在Linux静态函数库和动态函数库是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux静态函数库和动态函数库是什么
2023-06-28

C++静态库与动态库文件怎么生成和使用

这篇文章主要介绍“C++静态库与动态库文件怎么生成和使用”,在日常操作中,相信很多人在C++静态库与动态库文件怎么生成和使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++静态库与动态库文件怎么生成和使用
2023-07-05

linux生成(加载)动态库静态库和加载示例方法

动态库的生成: 1、#include #include "src.h" int sum(int a,int b){return (a+b);}2、#ifndef __SRC_H_
2022-06-04

Android静态库如何使用

要使用Android静态库,需要按照以下步骤进行操作:1. 将静态库文件(通常是以`.a`或`.lib`为后缀)放在你的Android项目的`libs`文件夹中。如果没有`libs`文件夹,可以手动创建一个。2. 在你的Android项目的
2023-08-23

linux下静态链接库和动态链接库的区别有哪些

这篇文章主要讲解了“linux下静态链接库和动态链接库的区别有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“linux下静态链接库和动态链接库的区别有哪些”吧!
2023-02-07

Linux系统如何配置动态IP、静态IP

这篇文章将为大家详细讲解有关Linux系统如何配置动态IP、静态IP,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. 配置动态IP(dhcp)本例的操作系统是Centos 7。\1. 进入网络脚本配置目
2023-06-28

Linux中如何使用动态库函数

这篇文章将为大家详细讲解有关Linux中如何使用动态库函数,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Linux动态库函数的详解加载动态库void *dlopen(const char *
2023-06-09

Java项目中如何实现动态与静态编译

本篇文章为大家展示了Java项目中如何实现动态与静态编译,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java中的动态和静态编译实例详解首先,我们来说说动态和静态编译的问题。 Q: java和j
2023-05-31

c语言静态库如何反编译

在C语言中,静态库是以二进制形式存储的,因此无法直接进行反编译。静态库是由编译器将多个目标文件打包成一个文件,其中包含了目标文件的机器码以及一些元信息。如果你想查看静态库中的内容,可以使用一些工具进行反汇编,例如objdump(Linux)
2023-09-29

编程热搜

目录