一文搞懂系列——你真的了解如何生成动态库了吗?

引言

动态库的编译,这有什么难度,这不是手到擒来的事情吗?无非不就是:

gcc -FPIC -shared -o libxxx.so  *.o  *.c  

我若是提出这些需求场景,阁下又如何应对呢?

  • 动态库A依赖其他部分提供的能力。但是却不想将内部的能力暴露出去
  • 动态库A依赖外部函数func_xxx,但是该符号即可能存在我们自己的库B中,也可能存在客户动态库C中。如何保证调用指定接口
  • 对外提供的库,如何让客户只能访问指定接口,实现其它接口的隐藏等。

至此你还能面不改色,自信的说:动态库编译简单吗?嘴角颤抖,不屈的低语:就是简单

也有朋友可能就会说:“现实工作中怎么会有这么奇葩的要求?就是你难为人,没事找事”。但是我想说的是,这些场景真的很常见,我在工作中就遇到过,不妨听我细说。

-Wl,–exclude-libs,ALL

工作场景:当今IT行业,一个产品的输出,基本都是有多个部门相互合作,紧密配合才能实现的。而各个部门之间的常见的配合方式就是提供SDK。比如:我之前在海康是做门禁产品的。其中有一个重要功能就是人脸识别。该功能流程可以分解

视频流获取 --> 提取图片帧 --> 人脸识别算法获取唯一ID --> 比对数据库中的ID --> 放行

其中视频流获取 --> 提取图片帧是bsp团队开发,他们提供动态库libB.a,我们调用其中对应接口。人脸识别算法计算唯一ID则是研究院团队提供的算法库libC.a。比对数据库中的ID --> 放行则是我们团队的开发内容。我们对外提供libA.so。

很明显我们,我们仅仅是做门禁业务开发,总不能把BSP团队或研究院的核心能力也提供给甲方吧?否则一定要加钱的。

但是我们该怎么做呢?因为我们知道,正常编译静态库libC.so的方式,肯定会将bsp和研究院提供的能力对外开放。客户集成时,是可以直接引用到libA.a和libB.a的对外接口。代码示例如下:

//a.c
extern int printf(char* ftm,...);
int a()
{
    printf("i'am liba.so");
    return 0;
}

//b.c
extern int printf(char* ftm,...);
int b()
{
    printf("i'am libb.so");
}

//c.c
extern int a(void);
extern int b(void);

int c()
{
    a();
    b();
    return 0;
}

编译:

yihua@ubuntu:~/test/1207$ gcc -c a.c
yihua@ubuntu:~/test/1207$ ar rcs -o libA.a a.o
yihua@ubuntu:~/test/1207$ gcc -c b.c
yihua@ubuntu:~/test/1207$ ar rcs -o libB.a b.o
yihua@ubuntu:~/test/1207$ gcc -FPIC -shared -o libC.so c.c -lA -lB -L.

符号关系:

如图所示,外部是可以通过libC.so去直接调用libA.a和libB.a的接口

如何解决这个问题呢?

链接器为我们提供了 -Wl,–exclude-libs 参数选项:隐藏静态库文件的符号。

我们加上编译选项再试试。

yihua@ubuntu:~/test/1207$
yihua@ubuntu:~/test/1207$ gcc -FPIC -shared -o libC.so c.c -L.  -Wl,--exclude-libs,ALL -lA -lB
yihua@ubuntu:~/test/1207$

符号关系:

由图可知,libA.a 和 libB.a的内部符号已经被隐藏了。完结,撒花~~~

-Wl,-Bsymbolic

工作场景:在工作中,我们无法避免的会依赖其它动态库。比如:我司开发的SDK libA.so底层用到了mqtt通信,因此会依赖开源库libpaho-mqtt3c.so,但是我司对内部源码做了一些定制化修改;同时,我们也依赖第三方供应商的SDK libB.so,并且他们内部也采用了mqtt协议通信,同样集成了mqtt开源库,也许他们也在内部做了定制化处理。

关系如下:

分析:

情况一:当admfotaApp运行时,链接器会根据它的动态库依赖关系,加载相应的动态库。而libpaho-mqtt3c.so仅会加载一次。之后再进行符号链接时,就会出现异常。—— 加载库了非预期的库

情况二:会导致mqtt开源库代码段被加载两次,也就是说进程中会有两套相同的符号和对应的代码段。libB.so和libA.so在进行符号链接时,可能就会出现异常。 —— 符号链接时出现问题

示例代码如下:

//a.c
extern int printf(const char* ftm,...);
int a()
{
    printf("i‘am OEM a\n");
}

int c()
{
    printf("i'am OEM c\n");
}

//b.c
extern int printf(const char* ftm,...);
extern int c(void);
extern int d(void);
int b()
{
    printf("i‘am abup a\n");
    c();
    d();
    return 0;
}

//c.c
extern int printf(const char* ftm,...);
int c()
{
    printf("i‘am abup c\n");
}

//d.c
extern int printf(const char* ftm,...);
int d()
{
    printf("i‘am abup d\n");
}

//main.c
extern int printf(const char* ftm,...);
extern int a(void);
extern int b(void);
int main()
{
        a();
        b();
        return 0;
}

编译如下:

gcc -c c.c
gcc -c d.c
ar -crs -o libC.a c.o d.o   // 生成静态库
gcc -FPIC -shared -o libB.so b.c -lC -L.    //从这可以看出,b.c期望时引用c.c中的c()
gcc -FPIC -shared -o libA.so a.c
gcc main.c -o main -lA -lB -lC -L.

运行:

由上可知:输出内容是非预期的。我们更新一下编译命令gcc main.c -o main -lB -lA -L.,运行结果如下:

链接库的顺序不一样,居然会有不一样的结果?这是为什么呢?有兴趣的朋友可以搜索:全局符号介入相关知识点。或参考我的一篇博客:全局符号介入引起的问题

针对该场景如何处理呢?

链接器中的-Wl,-Bsymbolic参数:告诉链接器强制使用本地的符号,也就是说,编译libB.so时,就确定符号地址。不需要等待运行时再链接。
比如我们在编译main.c时,增加该参数:

gcc -FPIC -shared -o libB.so b.c -lC -L. -Wl,-Bsymbolic
gcc main.c -o main -lA -lB -L.

输出:

完结撒花~~~。

有兴趣的同学可以通过反汇编查看增加-Wl,-Bsymbolic参数前后,libB.so的汇编内容。

总结

本文从两个实际存在的场景,向大家介绍了动态库生成过程中的一些特定需求。简单介绍了 -Wl,-Bsymbolic-Wl,–exclude-libs,ALL两个链接属性及使用方式。

当然很多其它常用的参数比如:-fvisibility=hidden-Wl,--whole-archive。有兴趣的朋友可以了解一下。

若我的内容对您有所帮助,还请关注我的公众号。不定期分享干活,剖析案例,也可以一起讨论分享。

我的宗旨:

踩完您工作中的所有坑并分享给您,让你的工作无bug,人生尽是坦途

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

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

相关文章

网络层(1)——概述

一、概述 网络层毫无疑问是最复杂的一层,涉及到大量的协议与结构的内容。在如今主流的设计中,大家都会把网络层分成两个部分:数据平面、控制平面。其中数据平面指的是网络层中每台路由器的功能,它决定了到达路由器端口输入链路之一…

马蹄集 oj赛(双周赛第十六次)

目录 ​圣诞树上的星星 军团大战 堆煤球 武力对决 小码哥教数学 小码哥玩字母独 跳跳棋 激光扫描游戏 数数游戏 小狗巴克 魔塔密码 地狱尖兵 3D眩晕 圣诞树上的星星 难度:青铜 时间限制: 1秒占用内存:64M 小码哥在过圣诞节! 小码哥家里有很多个星星 *&#xff0c…

热烈祝贺许战海老师成为北京湖南商会特聘专家!

在北京的初冬时节,一股商业的暖流在世纪华天大酒店的湖南厅中涌动。2023年12月3日下午,这里迎来了一场盛大的聚会——北京湖南企业商会成立20周年的预热活动之一:“湘商大讲堂”。这不仅是一次庆祝,更是一次对未来的展望&#xff…

在Pwn中,为什么时长需要栈对齐?

Index 介绍知识要点正文 介绍 在 Pwn 的学习中,对于初学者常常会遇到这个问题: 找到了溢出点,并且知道如何溢出,但是不知道为什么自己的Payload并没有成功,Pwntools报错EOF: 今天趁着有时间,来…

C++ 指针进阶

目录 一、字符指针 二、指针数组 三、数组指针 数组指针的定义 &数组名 与 数组名 数组指针的使用 四、数组参数 一维数组传参 二维数组传参 五、指针参数 一级指针传参 二级指针传参 六、函数指针 七、函数指针数组 八、指向函数指针数组的指针 九、回调函…

HBase 使用JDK21

HBase 使用JDK21 启动zookeeper和hadoop 创建软件目录 mkdir -p /opt/soft cd /opt/soft下载软件 wget https://dlcdn.apache.org/hbase/2.5.6/hbase-2.5.6-hadoop3-bin.tar.gz解压 hbase tar -zxvf hbase-2.5.6-hadoop3-bin.tar.gz修改 hbase 目录名称 mv hbase-2.5.6-had…

圣诞将至—C语言圣诞树代码来啦

文章目录 圣诞将至—C实现语言圣诞树源码 圣诞将至—C实现语言圣诞树 圣诞树 源码 #define _CRT_SECURE_NO_WARNINGS#include <stdio.h> #include <math.h> #include <stdlib.h> #include <windows.h> #include <time.h> #define PI 3.14159265…

深眸科技以机器视觉高性能优势,为消费电子行业提供优质解决方案

机器视觉技术近年来发展迅速&#xff0c;基于计算机对图像的处理与分析&#xff0c;能够识别和辨别目标物体&#xff0c;被广泛应用于人工智能、智能制造等领域。 机器视觉凭借着高精度、高效率、灵活性和可靠性等优势&#xff0c;不断推进工业企业生产自动化和智能化进程&…

论ChatGPT让程序员提升效率—掌握时代工具风口修炼之道【文末送书-02】

文章目录 一.论ChatGPT让程序员提升效率—掌握时代工具风口修炼之道二.ChatGPT在代码编写中的应用2.1 快速解决问题&#xff1a;2.2 优化代码结构&#xff1a;2.3 ChatGPT的学习过程2.4 ChatGPT的自定义训练 三.文末推荐与福利免费包邮送出4本&#xff01;3.2领书方式 一.论Cha…

java群聊聊天程序

先运行服务端&#xff0c;如果不先连接服务端&#xff0c;就不监听&#xff0c;那客户端不知道连接谁 服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class QLFWD{public static ServerSocket server_socket;public static ArrayList<S…

力扣刷题day3(移除元素,找出字符串中的第一个不匹配项的下标,搜索插入位置)

题目1&#xff1a;27.移除元素 思路1和代码&#xff1a; //由于题目要求删除数组中等于 val\textit{ val }val 的元素&#xff0c;因此输出数组的长度一定小于等于输入数组的长度&#xff0c;我们可以把输出的数组直接写在输入数组上。可以使用双指针&#xff1a;右指针 righ…

“掌握高效视频分割技巧,降低误差,提高精度“

如果你是一名视频编辑爱好者或者专业人士&#xff0c;那么你一定会在视频剪辑的过程中遇到各种挑战。其中&#xff0c;如何准确高效地进行视频分割是一个至关重要的问题。现在&#xff0c;我们将向你展示一种全新的解决方案&#xff0c;帮助你轻松解决这些问题。 首先第一步&a…

灯塔资产管理系统魔改版搭建(ARL-Puls)

免责声明 文章仅做经验分享用途&#xff01;利用本文章所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任&#xff0c;一旦造成后果请自行承担&#xff01;&#xff01;&#xff01; 简介 ARL-Puls是基于斗…

pycharm使用Anaconda中的虚拟环境【我的入门困惑二】

Anaconda的作用 Anaconda的存在&#xff0c;使得一台电脑上可以存在多个不同版本的python和相应的包&#xff0c;这解决了多个项目运行时&#xff0c;所需要的python和包版本不同的问题。 本文内容 今天就来简单说说如何在pycharm使用Anaconda中的虚拟环境。 详细介绍 首先…

Linux | tar,bc,uname指令

Linux | tar,bc,uname指令 文章目录 Linux | tar,bc,uname指令tar指令【重要】bc指令uname –r指令 tar指令【重要】 tar [-cxtzjvf] 文件与目录 … 参数&#xff1a; -c &#xff1a;建立一个压缩文件的参数指令(create 的意思)&#xff1b;-x &#xff1a;解开一个压缩文件的…

静态住宅代理IP怎么用?有何优势?

在全球互联网的广阔天地里&#xff0c;网络地理限制常常成为用户访问不同国家和地区内容的障碍。这时&#xff0c;住宅代理IP显得尤为重要。住宅代理IP&#xff0c;顾名思义&#xff0c;是指那些直接分配给家庭宽带用户的IP地址。与数据中心IP或商业IP相比&#xff0c;它们更能…

iOS-打包上架构建版本一直不出现

iOS开发过程中&#xff0c;打包上架苹果审核是一个不可或缺的环节。说实话&#xff0c;这个问题我遇见两次了&#xff0c;为了让自己长点记性&#xff0c;决定写下来。首先&#xff0c;列举几种情况&#xff1a; 1.iPa包上传至App store后&#xff0c;一个小时内不显示构建版本…

springboot3.0更新后,idea创建springboot2.x项目

springboot3.0更新后&#xff0c;idea创建springboot2.x项目 点击以下红色框中的按钮 出现了如下图所示&#xff1a; 到这里我们发现没有jdk8的版本&#xff0c;不要慌&#xff0c;我们可以先在这里选择21&#xff0c;然后进入到真正的项目中手动去修改这个jdk的版本&#xff0…

【JavaScript】JS——Map数据类型

【JavaScript】JS——Map数据类型 什么是Map?特性Map与Object的比较 map的创建map的属性map相关方法map的遍历 什么是Map? 存储键值对的对象。 能够记住键的原始插入顺序任何值&#xff08;对象或原始值&#xff09;都可以作为键或值。 特性 Map中的一个键只能出现一次&am…

VBA技术资料MF93:将多个Excel表插入PowerPoint不同位置

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…