Linux共享库基础及实例

共享库是将库函数打包成一个可执行文件,使得其在运行时可以被多个进程共享。

目标库

回顾下构建程序的一种方式:

将每个源文件编译成目标文件,再通过链接器将这些目标文件链接组成一个可执行程序。

gcc -g -c prog.c mod1.c mod2.c
gcc -g -o prog prog.o mod1.o mod2.o

库分为静态的和共享的

静态库

静态库是一个保存所有被添加到其中的目标文件的副本的文件。其名称形式libname.a

可以通过ar命令来创建和维护静态库

ar options archive object-files ...
#比如创建静态库
ar r libtest.a test1.o test2.o test3.o
#比如从静态库中删除一个模块
ar d libtest.a test2.o

使用静态库有两种方法

  • gcc -g -o prog prog.o libtest.a

  • gcc -g -o prog prog.o -Lxxx -ltest, 通过-L执行搜索目录和-l指定库名称

创建共享库

静态库有一些缺陷:

  • 多个静态库如果都使用到同一个目标文件,那么存储同一个目标文件的多个副本将会浪费磁盘空间

  • 如果多个程序都使用到了这个同一个目标文件,那么每个程序会在虚拟内存中独立保存一份该目标文件的副本,提高了整体虚拟内存使用量

  • 如果这同一个目标文件修改了, 那么使用到这个目标文件的多个静态库都要重新链接

所以,需要设计出共享库机制。

共享库的目标思想是目标文件的单个副本由所有需要使用它的程序共享

由第一个需要使用该目标文件的程序启动时,将该目标文件的副本运行加载进内存,后面的程序如果也需要使用该目标文件,直接使用已经被加载进内存的副本即可。

虽然共享库的代码是共享的,但其中的变量不是共享的,每个使用库的程序会拥有自己在库中定义的全局和静态变量的副本。

创建一个共享库

gcc -g -c -fPIC -Wall mod1.c mod2.c mod3.c
gcc -g -shared -o libfoo.so mod1.o mod2.o mod3.o

共享库的前缀是lib,后缀是.so

-fPIC选项:编译器应该生成位置独立的代码,这样共享库代码可以放到任意一个虚拟地址处。

也可以使用一行命令来生成共享库

gcc -g -fPIC -Wall mod1.c mod2.c mod3.c -shared -o libfoo.so

使用共享库也有两种方法

  • gcc -g -o prog prog.o libfoo.so

  • gcc -g -o prog prog.o -Lxxx -lfoo, 通过-L执行搜索目录和-l指定库名称

程序启动时可以通过LD_LIBRARY_PATH来指定库的位置。

共享库别名soname

如果一个共享库有别名soname,则静态链接时会将soname嵌入到可执行文件中,而不使用真实名字。

gcc -g -c -fPIC -Wall mod1.c mod2.c mod3.c
gcc -g -shared -Wl,-soname,libbar.so -o libfoo.so mod1.o mod2.o mod3.o

通过**-Wl,-soname**参数设置共享库libfoo.so的别名为libbar.so,这样程序在链接共享库libfoo.so的时候嵌入的就是libbar.so名字,所以还需要一步,创建软连接:

ln -s libfoo.so libbar.so

请添加图片描述

soname的目的是为了提供一层间接层,使得可执行程序能够在运行时使用与链接时使用的库不同的(但兼容的)共享库

版本和命名

真实名字命名规则

libname.so.major-id.minor-id,比如libdemo.so.1.0.1,第一个数字是主版本号,第二个数字是次版本号,第三个数字是该次版本中的修订号或补订号

soname命名规则

libname.so.major-id,比如libdemo.so.1,只需要包含主版本号。

libname.so.1 --> libdemo.so.1.0.1

通常还会创建一个链接器名称,比如libdemo.so,没有版本号。链接器铭名称可以链接到soname也可以链接到真实名字,一般链接到soname。

libname.so --> libname.so.1
libname.so.1 --> libname.so.1.0.1

请添加图片描述

动态加载库

在linux中可以通过dlopen API组来打开使用共享库。

构建程序时必须使用-ldl选项链接libdl库

主要的函数有dlopen(), dlsym(), dlclose(), dlerror()等:

#include <dlfcn.h>
void *dlopen(const char *filename, int flags); //打开共享库
void *dlsym(void *handle, const char *symbol); //查找符号
int dlclose(void *handle);    //关闭共享库
char *dlerror(void);        //错误诊断

控制符号可见性

如果共享库中的某个函数不想被导出symbol给外部访问,可以怎么做?

  • C程序中可以使用static关键词使得函数符号私有

  • gcc编译器提供了一个声明特性,与static效果类似

    void __attribute__((visibility("hidden"))) fun(void) { }
    

LD_PRELOAD

LD_PRELOAD环境变量的设置可以使得程序预加载指定的库,或者通过文件**/etc/ld.so.preload**来控制预加载库也是一样的。

LD_DEBUG

LD_DEBUG环境变量可以帮助监控动态链接器到底在搜索那些库,比如

LD_DEBUG=libs xxx可以监控程序xxx执行时搜索的库的路径。

代码实例

源码参考share_lib文件夹

testfun.c

#include <stdio.h>
void testfun(void) {
    printf("this is testfun\n");
}

dyload.c

#include <dlfcn.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    void *libHandle;
    void (*funcp)(void);
    const char *err;

    if (argc != 3 || strcmp(argv[1], "--help") == 0) {
        printf("usage: %s <lib-path> <func-name>\n", argv[0]);
        return 0;
    }

    libHandle = dlopen(argv[1], RTLD_LAZY);
    if (libHandle == NULL) {
        printf("dlopen: %s", dlerror());
        return -1;
    }

    (void) dlerror();
    *(void **)&funcp = dlsym(libHandle, argv[2]);
    err = dlerror();
    if (err) {
        printf("dlsym: %s\n", err); 
        return -1;
    }

    if (!funcp) {
        printf("%s is NULL\n", argv[2]);
        return -1;
    }else {
        printf("%s addr is: %p\n", argv[2], funcp);
    }

    (*funcp)();

    dlclose(libHandle);

    return 0;
}

Makefile

src1:=dyload.c
obj1:=dyload
src2:=testfun.c
obj2:=libtestfun.so

all:${src1} ${src2}
	gcc -g -fPIC -Wall ${src2} -shared -o ${obj2}
	gcc -g -o ${obj1} ${src1}
	./${obj1} ./${obj2} testfun
	
clean:
	@rm ${obj1} ${obj2}

执行效果,dyload执行时打印出libtestfun.so中testfun函数的地址,并执行该函数。

root@pc:share_lib# make
gcc -g -fPIC -Wall testfun.c -shared -o libtestfun.so
gcc -g -o dyload dyload.c
./dyload ./libtestfun.so testfun
testfun addr is: 0x7f694b0f8119
this is testfun

参考文献

《linux programming interface》part42-43

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023国赛数学建模思路 - 案例:粒子群算法

文章目录 1 什么是粒子群算法&#xff1f;2 举个例子3 还是一个例子算法流程算法实现建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 什么是粒子群算法&#xff1f; 粒子群算法&#xff08;Pa…

C/C++:C/C++在大数据时代的应用,以及C/C++程序员未来的发展路线

目录 1.C/C在大数据时代的应用 1.1&#xff1a;C/C数据处理 1.2&#xff1a;C/C数据库 1.3&#xff1a;C/C图像处理和计算机视觉 1.3.1&#xff1a;导读 2.C/C程序员未来的发展路线 2.1&#xff1a;图导 1.C/C在大数据时代的应用 C/C在大数据时代中仍然是一种被广泛应用的编…

如何使用Wireshark进行网络流量分析?

如何使用Wireshark进行网络流量分析。Wireshark是一款强大的网络协议分析工具&#xff0c;可以帮助我们深入了解网络通信和数据流动。 1. 什么是Wireshark&#xff1f; Wireshark是一个开源的网络协议分析工具&#xff0c;它可以捕获并分析网络数据包&#xff0c;帮助用户深入…

Python(八十五)格式化字符串

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

MySQL 主从配置

环境 centos6.7 虚拟机两台 主&#xff1a;192.168.23.160 从&#xff1a;192.168.23.163 准备 在两台机器上分别安装mysql5.6.23&#xff0c;安装完成后利用临时密码登录mysql数据修改root的密码&#xff1b;将my.cnf配置文件放至/etc/my.cnf&#xff0c;重启mysql服务进…

jsp 图书销售系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 图书销售系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

SpringBoot 使用 Sa-Token 完成权限认证

一、设计思路 所谓权限认证&#xff0c;核心逻辑就是判断一个账号是否拥有指定权限&#xff1a; 有&#xff0c;就让你通过。没有&#xff1f;那么禁止访问&#xff01; 深入到底层数据中&#xff0c;就是每个账号都会拥有一个权限码集合&#xff0c;框架来校验这个集合中是…

异步I/O优化Python代理程序性能

作为一名爬虫程序员&#xff0c;你是否曾经遇到过需要处理大量网络请求的情况&#xff1f;你是否想要提高你的Python代理程序的性能&#xff0c;让它更快、更高效&#xff1f;别担心&#xff0c;我来给你分享一些关于异步I/O如何优化Python代理程序性能的实用知识。 首先&…

Haproxy 搭建集群实验

Haproxy HAProxy是可提供高可用性、负载均衡以及基于TCP和HTTP应用的代理&#xff0c;是免费、快速并且可靠的一种解决方案。 HAProxy非常适用于并发大&#xff08;并发达1w以上&#xff09;web站点&#xff0c;这些站点通常又需要会话保持或七层处理。 HAProxy的主要特性 可…

Prometheus+Grafana+AlertManager监控SpringBoot项目并发送邮件告警通知

文章目录 PrometheusGrafanaAlertManager监控平台搭建新建SpringBoot项目为Prometheus提供指标新建项目&#xff0c;引入依赖新建接口&#xff0c;运行程序 推送指标到pushgateway 开始监控Grafana连接Prometheus数据源导入Grafana模板监控SpringBoot项目 邮件告警通知同系列文…

SAP‘s ECC6 EoL(End of Life) 支持服务声明 2027?

前言 一、EoL公告信息&#xff0c;2027&#xff1f; 二、继续使用ECC6.0的选项 1.引入第三方支持 2.S/4 HANA 3.SAP Business ByDesign 4.SAP Business One 总结 最新的公告是&#xff1a;2027年&#xff0c;SAP ECC 6.0将停止得到支持&#xff0c;并退出主流SAP支持&am…

PostgreSQL-研究学习-介绍与安装

PostgreSQL-预研 是个很厉害的数据库的样子 ψ(*&#xff40;ー)ψ 官方文档&#xff1a;http://www.postgres.cn/docs/12/ 总的结论和备注 PgSQL 支持对JSON的支持很强大&#xff0c;以及提供了很多数学几何相关的数据类型【例&#xff1a;点&#xff0c;线条&#xff0c;几何…

亿级短视频,如何架构?

说在前面 在尼恩的&#xff08;50&#xff09;读者社群中&#xff0c;经常指导大家面试架构&#xff0c;拿高端offer。 前几天&#xff0c;指导一个年薪100W小伙伴&#xff0c;拿到字节面试邀请。 遇到一个 非常、非常高频的一个面试题&#xff0c;但是很不好回答&#xff0…

【Java 高阶】一文精通 Spring MVC - 转换器(五)

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

table,设置 数据相同时, 合并列

<el-table :data"tableData" :span-method"objectSpanMethod" border style"width: 100%" show-summary><el-table-column type"index" label"序号" width"100" /><el-table-column prop"dat…

红日靶场(一)vulnstack1 渗透过程分析

文章目录 环境搭建信息收集PhpMyAdmin 后台 Getshellinto outfileMysql日志文件写入shell CS后渗透MSF后渗透知识补充nmap参数分类参数速查表 dirsearch 环境搭建 ip段设置 kali (coleak)&#xff1a;192.168.145.139 Windows 7 (stu1)&#xff1a;192.168.10.181、192.168.1…

Java后端:html转pdf实战笔记

1、htmltopdf有什么用? htmltopdf 是一款基于wkhtmltopdf技术的html转pdf文档java类库,支持html转pdf和url转pdf。 2、什么是wkhtmltopdf wkhtmltopdf是一个用webkit网页渲染引擎开发的用来将html转成 pdf的工具,可跟多种脚本语言进行集成来转换文档,有windows、linux等平…

云南森林火灾vr消防模拟安全演练系统训练消防员火灾和事故的适应和应对能力

据统计,每一场破坏性地震发生后,会引发次生的灾害,而火灾是其中之一。导致火灾的原因,推测是地震时使供电线路短路,引燃易燃物,火灾就随即发生。所以,在日常生活中,定期的消防演练还是非常必要的, VR消防&#xff0c;是VR公司深圳华锐视点利用VR虚拟现实技术&#xff0c;将VR和…

发力服务业务,龙湖集团半程领跑赢在“智慧”

成立三十载&#xff0c;龙湖集团一直是房地产行业“特立独行”的存在。 一方面&#xff0c;龙湖在对外战略方面长期量入为出&#xff0c;从不背上过重的“包袱”。 不久前&#xff0c;一则消息引发市场关注&#xff1a;龙湖集团提前偿还17亿元债务&#xff0c;已基本全部还清…

2023年国赛 高教社杯数学建模思路 - 案例:粒子群算法

文章目录 1 什么是粒子群算法&#xff1f;2 举个例子3 还是一个例子算法流程算法实现建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 什么是粒子群算法&#xff1f; 粒子群算法&#xff08;Pa…