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.soall:${src1} ${src2}gcc -g -fPIC -Wall ${src2} -shared -o ${obj2}gcc -g -o ${obj1} ${src1}./${obj1} ./${obj2} testfunclean:@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
相关文章:

Linux共享库基础及实例
共享库是将库函数打包成一个可执行文件,使得其在运行时可以被多个进程共享。 目标库 回顾下构建程序的一种方式: 将每个源文件编译成目标文件,再通过链接器将这些目标文件链接组成一个可执行程序。 gcc -g -c prog.c mod1.c mod2.c gcc -g …...

java八股文面试[java基础]——final 关键字作用
为什么局部内部类和匿名内部类只能访问final变量: 知识来源 【基础】final_哔哩哔哩_bilibili...

Redis 分布式锁存在什么问题 ?如何解决 ?
目录 1. 如何实现分布式锁 2. Redis 分布式锁存在什么问题 2.1 解决死锁问题 2.2 解决锁误删问题 1. 如何实现分布式锁 Redis 天生就可以作为一个分布式系统来使用,所以它实现的锁都是分布式锁。 Redis 可以通过 setnx(set if not exists)…...

n5173b是德科技keysight N5173B信号发生器
产品概述 是德科技/安捷伦N5173B EXG模拟信号发生器 当您需要平衡预算和性能时,是德科技N5173B EXG微波模拟信号发生器是经济高效的选择。它提供解决宽带滤波器、放大器、接收机等参数测试的基本信号。执行基本LO上变频或CW阻塞,低成本覆盖13、20、31.…...
React源码解析18(10)------ 实现多节点的Diff算法
摘要 在上一篇中,实现了多节点的渲染。但是之前写得diff算法,只能适用于单节点的情况,例如这种情况: <div><p><span></span></p> </div>如果对于多节点的情况: <ul><…...
Linux指令篇!
Linux 是一个广泛使用的开源操作系统,以下是一些常用的 Linux 知识点和指令: 1. 文件和目录操作: - ls:列出目录内容 - cd:切换目录 - pwd:显示当前工作目录 - mkdir:创建目录 - touch…...
Vue2学习笔记のVue组件化编程
目录 Vue组件化编程非单文件组件基本使用几个注意点组件的嵌套VueComponent一个重要的内置关系 单文件组件index.htmlmain.jsApp.vueSchool.vueStudent.vue 各位小伙伴们好呀,不知道上一篇文章你是否有收获!这篇是Vue2学习笔记第二篇,也是Vue…...

跨境电商儿童沙画办理EN71测试标准
儿童沙画就是小孩子玩的那种用彩色沙子或者彩色墨水,在有图形轮廓的纸片上去绘画,可以按照儿童沙画底板上的人物轮廓线条,动物线条,风景线条,动漫线条,去添加自己喜欢的颜色,让单调的线条变成自…...

chrome浏览器账号密码输入框自动填充时背景色不变
处理前 使用延时的方式解决 .login-box input,password:-webkit-autofill .login-box input,password:-webkit-autofill:hover, .login-box input,password:-webkit-autofill:focus, .login-box input,password:-webkit-autofill:active {-webkit-transition-delay: 999999…...

【ARM】Day9 cortex-A7核I2C实验(采集温湿度)
1. 2、编写IIC协议,采集温湿度值 iic.h #ifndef __IIC_H__ #define __IIC_H__ #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" #include "led.h" /* 通过程序模拟实现I2C总线的时序和协议* GPIOF ---> AHB4* I2C1_S…...

【Leetcode】移动零
移动零 题目描述算法描述编程代码 链接: 移动零 题目描述 算法描述 编程代码 class Solution { public:void moveZeroes(vector<int>& nums) {//题目要求不可以复制数组,开辟额外空间int dest -1,curr 0;for(;curr < nums.size();curr){if(nums[cu…...

数据结构入门 — 顺序表详解
前言 数据结构入门 — 顺序表详解 博客主页链接:https://blog.csdn.net/m0_74014525 关注博主,后期持续更新系列文章 文章末尾有源码 *****感谢观看,希望对你有所帮助***** 文章目录 前言一、顺序表1. 顺序表是什么2. 优缺点 二、概念及结构…...

SimpleCG绘图函数(9)--绘制各种线条
一、所有线段函数概述 可填充图形绘制函数都介绍完了,还有一些特殊线条的绘制将在本篇进行讲解。所有特殊线条函数如下所示,其中还有一个区域填充函数floodfill比较特殊,是配合线条函数使用的: //绘制一系列折线段 //折线段以一组…...

RISCV 6 RISC-V加载存储指令
RISCV 6 RISC-V加载存储指令 1 RV32I Load and Store Instructions1.1 LOAD instructions1.1.1 加载指令的指令格式1.1.2 加载指令在使用时需要注意的点 1.2 STORE instructions1.2.1 存储指令的指令格式1.2.2 存储指令在使用时需要注意的点 2 RV64 Load and Store Instruction…...
木叶飞舞之【机器人ROS2】篇章_第二节、turtlebot3安装
没有真实小车的情况下,利用gazebo的仿真,操作小乌龟来学习ros2。废话不多说,直接上命令。 Install Gazebo sudo apt install ros-humble-gazebo-*Install Cartographer 假如前一节未安装源码版本的cartographer,那就安装apt版本…...

【论文阅读】自动驾驶安全的研究现状与挑战
文章目录 摘要1.引言1.1.自动驾驶安全1.2.攻击面1.3.内容和路线图 2.自动驾驶技术2.1.组成2.2.技术 3.传感器安全3.1.照相机3.2.GNSS(全球导航系统)/IMU(惯性测量单元)3.3.超声波传感器3.4.毫米波雷达3.5.激光雷达3.6.多传感器交叉…...

标签打印小工具 选择图片打印,按实际尺寸打印。可旋转图片
您可以尝试使用以下标签打印工具: 柯尼卡美能达标签打印机:功能齐全、易于使用的打印机,支持各种标签尺寸和类型。 赛门铁克标签打印机:高速打印、可靠性强的打印机,支持多种操作系统和软件。 齐柏林标签打印机&…...

什么是深拷贝和浅拷贝?
面试回答 在计算机内存中,每个对象都有一个地址,这个地址指向对象在内存中存储的位置。当我们使用变量引用一个对象时,实际上是将该对象的地址赋值给变量。因此,如果我们将一个对象复制到另一个变量中国,实际上是将对象…...

安装docker服务及docker基本操作
一、docker安装(yum安装) 基于centos7 1.添加docker-ce 源信息 安装依赖包(yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序需要device-mapper-persistent-data 和 lvm2) yum install yum-…...
【项目经验】:项目中下拉框数据太多造成页面卡顿(二)
一.项目需求 下拉框下拉列表数据是由后端返回的,而且他会变化,所以数据不是写死的而且数据量大。上一篇博客http://t.csdn.cn/sSNTa我们是用的数据懒加载的方式,这次我们使用远程搜索的方式解决这个问题。 二.用到的组件方法介绍 filterabl…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...