Linux环境编译动态库

简介: Linux环境编译动态库

我们之前已经 编译过 libstar.a 静态库 给 zeus(宙斯)跟 poseidon(波塞冬)使用。由于 静态库 会把内容拷贝进去程序里面,所以会加大磁盘存储空间。

如果有100个软件都用到 某个库,如果这个库是静态链接到100个软件,数据量就会很大,所以操作系统一些底层库,都是以动态库的方式提供给上层程序调用的。

而且动态库还有一个好处,可以很方便单独更新某个动态库,可以利用动态库的机制做一个插件系统。

我们如何编译出 libstar.so 动态库呢?这个就是本文的重点。

相关文件 sun.c , moon.c 跟 earth.c 还是之前在 universe 目录,提取码:mku9 。用以下命令即可 编译出 libstar.so 动态库。

gcc -c -o sun.o sun.c
gcc -c -o moon.o moon.c
gcc -c -o earth.o earth.c 
gcc -fPIC -shared -o libstar.so sun.o moon.o earth.o

-fPIC 是编译选项,PIC是 Position Independent Code 的缩写,表示要生成位置无关的代码。执行结果如下:



现在用 objdump 查看一下这个动态库的汇编代码。

objdump -d libstar.so > star-so-dump.txt

从上图可以看到,动态库跟之前的静态库不太一样,两个 call 的地址已经被修正。这是为什么呢?不是说动态链接,只有在运行的时候才会进行链接。

为什么此时此刻,就会修正 call 的地址?

注意看 moon_rotate@plt 后面的 plt 全称是 Procedure Linkage Table (过程链接表),我们可以看以下 callq 590 会跳到哪里,如下:

上图中的 590 是硬盘文件中的偏移,偏移590 字节就能看到一样的二进制内容。上图中的三条汇编指令,实际根本不是我们之前定义的 moon_rate 函数的指令。

这个实际上是生成 动态库的时候,给call 00 00 00 的函数引用封装一层。通过 gdb 调试会会发现,程序是先 进入 moon_rate@plt ,然后再通过 jmpq 跳转到 真正的 moon_rate 函数。

这个过程可以理解为, 通过 Procedure Linkage Table 表,跳转到真正的函数。


我们再做一个实验,生成 libstar.so 动态库的时候,把 moon.o 删掉,不加入。看看 sun.o 里面对 moon_rate 的引用会不会被修正。

提醒:注意这个 libstar-err.so,这个漏了 moon.o 的动态库后面会用来显示一个错误的情况。

gcc -fPIC -shared -o libstar-err.so sun.o earth.o

从上图可以看到,即使没有 moon.o 依然会被修正。但是 这个 libstar-err.so 是有问题的,可以使用 ldd 加上 -r 选项进行模拟重定位函数,会发现找不到 moon_rorate 函数的实现。


因为 sun.o 里面调了 printf 函数,所以用 ldd 查看,可以发现 libstar.so 跟 libc.so 已经建立了链接。


现在把 libstar.so 拷贝到 zeus 项目,执行以下命令编译。

gcc -c -o zeus.o zeus.c
gcc -o zeus zeus.o libstar.so
./zeus

从上图可以看出,虽然可以顺利链接,生成 zeus 文件,但是运行的时候却报找不到 libstar.so 动态库,这是因为 Linux 环境默认不会从当前路径 加载动态库。而 Windows 环境会从当前路径 加载动态库。

那Linux 的加载器会从哪些目录搜索加载动态库呢?业界制定了一个 FHS (File Hierarchy Standard)标准,这个标准规定了一个系统中的系统文件应该如何存放,大部分Linux系统都遵循这个标准。

共享库的存放方式也在这个 FHS 标准里面,标准定义共享库可以放在 /lib , /usr/lib , /usr/local/lib 这 3个目录。所以运行加载动态库的时候,也会在这 3个目录搜索。

但是还有一个常规做法,在 /etc/ld.so.conf.d/ 添加自定义配置。我们查看一下 ld.so.conf 文件的内容,如下:

发现他是把其他的文件 include 进来的,所以我们需要创建一个自己的配置文件 /etc/ld.so.conf.d/star.conf ,内容如下:

# star default configuration
/usr/local/star/lib

然后创建目录 /usr/local/star/lib ,把 libstar.so 拷贝到 /usr/local/star/lib

此时,还需要 重新加载一下之前的 star.conf 配置,执行 命令 sudo ldconfig。再次 运行 zeus 就没有问题了,即使把当前目录的 libstar.so 删除也能运行,因为 运行的时候是从 /usr/local/star/lib 目录找动态库

上面我是直接 写 动态库全称来进行链接了,其实另一种更常用的链接动态库的语法是这样的。如下:

gcc -o zeus zeus.o -L/usr/local/star/lib -lstar

-L 是指定库的搜索路径。这里提醒一下,链接 跟 运行加载 是两个不同的操作。之前 在 /etc/ld.so.conf.d/star.conf 文件配置的是加载的路径。链接的时候还是需要用 -L 参数指定。


之前我们生成了一个 libstar-err.so 动态库,这个动态库是没有 moon.o 的,如果 zeus 项目使用这个动态库会怎样呢?把 libstar-err.so 拷贝到 /usr/local/star/lib,执行下面命令再次编译。

mv libstar-err.so /usr/local/star/lib
gcc -o zeus-err zeus.o -L/usr/local/star/lib -lstar-err

可以看到,链接器直接报错,找不到 moon_rotate 的函数实现。


相关阅读:

1,《C++静态库与动态库》- 吴秦


目录
相关文章
|
23天前
|
Web App开发 搜索推荐 Unix
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
【10月更文挑战第21天】Linux系统之MobaXterm远程连接centos的GNOME桌面环境
188 4
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
|
9天前
|
关系型数据库 MySQL Linux
Linux环境下MySQL数据库自动定时备份实践
数据库备份是确保数据安全的重要措施。在Linux环境下,实现MySQL数据库的自动定时备份可以通过多种方式完成。本文将介绍如何使用`cron`定时任务和`mysqldump`工具来实现MySQL数据库的每日自动备份。
27 3
|
9天前
|
监控 关系型数据库 MySQL
Linux环境下MySQL数据库自动定时备份策略
在Linux环境下,MySQL数据库的自动定时备份是确保数据安全和可靠性的重要措施。通过设置定时任务,我们可以每天自动执行数据库备份,从而减少人为错误和提高数据恢复的效率。本文将详细介绍如何在Linux下实现MySQL数据库的自动定时备份。
22 3
|
24天前
|
Ubuntu 应用服务中间件 Linux
Linux下搭建Nginx环境的搭建
Linux下搭建Nginx环境的搭建
|
19天前
|
Linux UED iOS开发
|
28天前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
36 3
|
17天前
|
Linux
Linux - 如何编译源码安装软件
源码编译安装通常包括三个步骤:1) `./configure` 检测平台特征和依赖项,生成 Makefile;2) `make` 编译源码,生成可执行文件;3) `make install` 将可执行文件安装到指定目录并配置环境变量。
31 0
|
安全 Linux 测试技术
配置Goby工具环境(win,linux,macOS)
配置Goby工具环境(win,linux,macOS)
801 2