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++静态库与动态库》- 吴秦


目录
相关文章
|
26天前
|
存储 Linux
Linux环境下删除大文件后磁盘空间未释放问题诊断流程。
以上诊断流程涉及Linux底层机制与高级管理技能结合之处,并需要管理员根据实际环境灵活调整诊断策略与解决方案。
94 8
|
2月前
|
Linux 数据安全/隐私保护 iOS开发
推荐Linux环境下效能优良的双向文件同步工具
综合上述条件,对于Linux环境下的双向文件同步需求,Unison 和 Syncthing 是两个非常出色的选择。它们都有良好的社区支持和文档资源,适用于不同规模的环境,从个人使用到商业部署。Unison 特别适合那些需要手动干预同步过程、需要处理文件冲突解决的场景。而 Syncthing 更加现代化,适合需要自动、实时的数据同步与备份的环境。对于选择哪一个,这将取决于个人的使用场景和具体需求。
278 16
|
2月前
|
安全 应用服务中间件 网络安全
在Linux环境部署Flask应用并启用SSL/TLS安全协议
至此,你的Flask应用应该能够通过安全的HTTPS协议提供服务了。记得定期更新SSL证书,Certbot可以帮你自动更新证书。可以设定cronjob以实现这一点。
180 10
|
1月前
|
Ubuntu 安全 Linux
Ubuntu 24.10 发行版登场:Linux 6.11 内核、GNOME 47 桌面环境
Ubuntu 24.10 还带来了 GNOME 47,增强了性能和稳定性,并引入了新功能。此版本的 Ubuntu 还默认在采用 Nvidia 显卡的硬件上切换到 Wayland,并在支持的硬件上默认使用开源的 Nvidia 560 内核模块。 另外需要注意的是,Ubuntu 24.10 是稳定版本,但作为非 LTS 版本,仅支持 9 个月。
|
1月前
|
安全 Linux 网络安全
Linux系统初步设置本地Git环境和生成SSH密钥的步骤。
现在您的Linux系统已经配置好了Git环境,并创建并添加了SSH密钥,可以安全地与远端仓库进行交互,无论是克隆、推送还是拉取操作。此过程确保了数据传输的安全并使版本控制流程更为顺畅。使用Git时应考虑定期更新并管理您的凭据,以确保安全性。
294 0
|
1月前
|
XML 缓存 Linux
在Linux环境下解决Visual Studio Code字体显示异常和字体替换方法。
解决Linux下VS Code字体显示异常,需要对Linux字体渲染机制有所理解,并对VS Code的配置选项进行合理设置。替换字体时则要通过系统字体配置或VS Code设置来完成。通过上述方法,可以有效地解决字体显示问题,从而提升代码编辑的视觉体验。
174 0
|
2月前
|
Kubernetes Linux 网络安全
Rocky Linux 8.9配置Kubernetes集群详解,适用于CentOS环境
初始化成功后,记录下显示的 `kubeadm join`命令。
155 0
|
前端开发 rax Linux
Linux 程序 Linux编译 Linux编译过程的来龙去脉
Linux 程序编译过程的来龙去脉 大家肯定都知道计算机程序设计语言通常分为机器语言、汇编语言和高级语言三类。高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如C,C++,Java,另一种是解释型语言,例如Python、Ruby、MATLAB 、JavaScript。
1279 0
|
2月前
|
监控 Linux 网络安全
Linux命令大全:从入门到精通
日常使用的linux命令整理
635 13
|
3月前
|
Linux 网络安全 数据安全/隐私保护
使用Linux系统的mount命令挂载远程服务器的文件夹。
如此一来,你就完成了一次从你的Linux发车站到远程服务器文件夹的有趣旅行。在这个技术之旅中,你既探索了新地方,也学到了如何桥接不同系统之间的距离。
475 21