C++ Linux动态库的编译和调用

C++动态库编译

采用g++编译C++动态库,命令如下:

g++ -fPIC -shared -o 动态库名 cpp文件名

1.1 关于fPIC选项 

首先了解动态库的载入时重定位。

一般linux的可执行文件都是elf格式(一种二进制文件格式),在可执行文件的头部包含了文件格式、加载地址、符号表等信息。当连接器链接生成可执行文件时,会将程序的加载地址写入到可执行文件的头中。在程序运行时,动态加载器将可执行文件载入文件头指定的加载地址位置,并加载该地址,开始从该地址处运行。由此可见,可执行文件的起始地址是在编译时就决定的。

#define EI_NIDENT 16
typedef struct{
	unsigned char e_ident[EI_NIDENT];
	Elf32_Half e_type;
	Elf32_Half e_machine;
	Elf32_Word e_version;
	Elf32_Addr e_entry;
	Elf32_Off e_phoff;
	Elf32_Off e_shoff;
	Elf32_Word e_flags;
	Elf32_Half e_ehsize;
	Elf32_Half e_phentsize;
	Elf32_Half e_phnum;
	Elf32_Half e_shentsize;
	Elf32_Half e_shnum;
	Elf32_Half e_shstrndx;
} Elf32_Ehdr;

最开头是16个字节的e_ident, 其中包含用以表示ELF文件的字符,以及其他一些与机器无关的信息。开头的4个字节值固定不变,为0x7f和ELF三个字符。

e_type 它标识的是该文件的类型。

e_machine 表明运行该程序需要的体系结构。

e_version 表示文件的版本。

e_entry 程序的入口地址。

e_phoff 表示Program header table 在文件中的偏移量(以字节计数)。

e_shoff 表示Section header table 在文件中的偏移量(以字节计数)。

e_flags 对IA32而言,此项为0。

e_ehsize 表示ELF header大小(以字节计数)。

e_phentsize 表示Program header table中每一个条目的大小。

e_phnum 表示Program header table中有多少个条目。

e_shentsize 表示Section header table中的每一个条目的大小。

e_shnum 表示Section header table中有多少个条目。

e_shstrndx 包含节名称的字符串是第几个节(从零开始计数)。

elf的依赖库查看

readelf -d main1 | grep NEEDED

elf各个section的header信息

readelf -S --wide main

以二进制方式打开某个可执行程序,可以看到开头就是ELF头信息

载入时重定位的缺点:

1、动态库的代码段不能在进程间共享:多个进程加载同一个动态库到各自不同的地址空间,导致代码段需要不同的重定位,所以最终每个引用该动态库的进程拥有一份该动态库代码段的不同拷贝。

2、代码段必须是可写的,增加了被攻击风险。

为了解决载入时重定位的问题,引入了PIC的概念,即位置无关代码。

1.2 关于shared选项

-shared用来创建动态库

1.3 测试demo

#include <iostream>
using namespace std;

void Get123Info()
{
	cout << "get info call success" << endl;
}
编译当前demo : g++ -fPIC -shared -o libtest1.so test.cpp

1.3.1 C++名字改编问题

生成的库进行查看当前库的符号,发现当前函数名被g++编译器改名了

这里涉及一个问题需要注意

名字改编(Name Mangling,或Name Decoration):在C++中,有函数重载的特性,所以编译器在编译时会出现符号名称相同的问题,为了解决这个问题,就有了名字改编。它将一些函数的额外信息加入到符号名中。

1.3.2 常规的动态库接口处理手段

如果我们在动态库的制作中,接受了这个名字改编,那对方调用加载这个符号时,就需要根据提供的so的实际符号名进行加载,那将很麻烦,所以一般都是采用C语言的规则来解决这个问题,即采用extern "C"的方式。

修改后的代码如下

#include <iostream>
using namespace std;

#ifdef __cplusplus
extern "C"
    __attribute__((visibility("default"))) void Get123Info()
    {
        cout << "get info call success" <<endl;
    }
#endif
再进行编译,查看符号和函数名一致了

二、C++动态库的调用

2.1 系统显式调用库

linux下C++动态库的加载和调用是采用<dlfcn.h>库进行显式调用

其中包括系统函数如下:

2.1.1 dlopen()

函数功能:打开一个动态库,并返回动态库的句柄

函数定义如下:

void * dlopen( const char * pathname, int mode);
其中第一个参数是库路径名称;

第二个参数是加载库的模式:

RTLD_LAZY:暂缓决定,在dlopen返回前,对于动态库中的未定义的符号不执行解析(只对函数引用有效,对于变量引用总是立即解析)

RTLD_NOW:立即决定,在dlopen返回前,解析出所有未定义的符号,如果解析不出来,在dlopen会返回NULL,错误为 undefined symbol:XXX...

作用范围:

RTLD_GLOBAL: 动态库中定义的符号可被其后打开的其他库重定位

RTLD_LOCAL: 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其他库重定位。如果没有指明是RTLD_GLOBAL还是RTLD_LOCAL,那么

默认是RTLD_LOCAL。

返回值:

成功返回库引用的handle,失败返回NULL

2.1.2 dlsym()

函数功能:从动态库中获取符号(全局变量与函数符号)地址,通常用于获取函数符号地

址。

函数定义:

void *dlsym(void *handle, const char *symbol);
其中第一个参数为动态库的句柄,第二个参数为符号名(可以理解为函数名)

返回值:

成功返回函数符号地址,失败返回NULL

2.1.3 dlclose()

函数功能:关闭动态库句柄,只有当此动态库的使用计数为0时,才会被真正的卸载。

函数定义:

int dlclose(void *handle);
其中入参为动态库句柄

返回值:

成功返回0,失败返回非0

2.1.4 dlerror()

函数功能:当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为 NULL时表示操作函数执行成功。

函数定义:

char *dlerror(void);
返回值:返回为空,表示执行成功,返回值不为空,返回具体报错信息

2.2 测试demo

g++编译命令如下:

g++ -o main1 main1.cpp -ldl -g

2.2.1 关于ldl选项

-ldl 是 g++ 编译器链接选项,它会将动态链接库 libdl.so 链接进可执行文件中,以便程序 可以调用 libdl 中定义的函数。使用该命令即可

2.2.2 demo代码

#include <iostream>
#include <dlfcn.h>
using namespace std;
typedef void (*Getinfo)();
int main()
{
	void* handle = dlopen("./libtest1.so", RTLD_LAZY);
	if (!handle)
	{
		return 0;
	}
	void* temp = dlsym(handle, "Get1234Info");
	if (temp)
	{
		Getinfo getinfo = reinterpret_cast<Getinfo>(temp);
		(*getinfo)();
	}
	else
	{
		cout << "dlsym error: " << dlerror() << endl;
	}
	dlclose(handle);
	return 0;
}

代码测试

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

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

相关文章

在线App封装技术:HTML5的新生命

HTML5封装的魅力所在HTML5带来了丰富的多媒体功能、地理位置服务、离线存储等特性&#xff0c;使得Web应用的体验更加接近原生App。封装HTML5到App中&#xff0c;可以大大缩短开发周期&#xff0c;降低开发成本&#xff0c;并且一次编写&#xff0c;多平台运行&#xff0c;极大…

ant-desgin的table的上移、下移

文章目录 html部分函数部分 html部分 <a-table :columns"columns" :data-source"dataList" :loading"listLoading" :pagination"false"><template #bodyCell"{ column, record, index }"><template v-if&qu…

Xline v0.6.1: 一个用于元数据管理的分布式KV存储

Xline是什么&#xff1f;我们为什么要做Xline&#xff1f; Xline是一个基于Curp协议的&#xff0c;用于管理元数据的分布式KV存储。现有的分布式KV存储大多采用Raft共识协议&#xff0c;需要两次RTT才能完成一次请求。当部署在单个数据中心时&#xff0c;节点之间的延迟较低&a…

2024Java高频面试题之MQ消息中间件,面试都问些什么?(附详细答案)

最近很多同学问我有没有java学习资料&#xff0c;我根据我从小白到架构师多年的学习经验整理出来了一份50W字面试解析文档、简历模板、学习路线图、java必看学习书籍 、 需要的小伙伴 可以关注我公众号&#xff1a;“ Tom聊架构 ”&#xff0c; 回复暗号&#xff1a;“ 578”即…

(人才测评)招聘数据分析师的入职测评方案

现在是一个大数据的时代&#xff0c;我们的车载导航、淘宝购物、包括人才招聘、都是大数据的产物&#xff0c;然而光靠数据堆积是没用的&#xff0c;所以如何高效的进行数据挖掘与分析&#xff0c;就成了每一件企业思考的问题。 一、 数据分析师的基本工作标准 1、 平时需要…

信息化和数字化的本质区别是什么?

信息化和数字化的本质区别是什么&#xff1f; 谢邀。前两年流行”信息化“&#xff0c;网上铺天盖地都是关于”信息化“的文章&#xff0c;这两年开始流行起“数字化”&#xff0c;于是铺天盖地都是“数字化”的文章&#xff0c;从数字化和信息化这两个关键词热度趋势就可以看…

qemu安装踩坑记(源码编译make版

qemu安装踩坑记&#xff08;源码编译make版 【写在前面】 本篇文章写于6.27号&#xff0c;发现写完但没发博客2333 大家好这里是β-AS&#xff0c;或者也可以喊我贝塔&#xff0c;或许也可也喊我be7a 没有人会永远学qemu&#xff0c;但永远会有人踩坑.jpg 依旧推荐一首歌 -1…

如何使用JS逆向爬取网站数据

引言&#xff1a; JS逆向是指利用编程技术对网站上的JavaScript代码进行逆向分析&#xff0c;从而实现对网站数据的抓取和分析。这种技术在网络数据采集和分析中具有重要的应用价值&#xff0c;能够帮助程序员获取网站上的有用信息&#xff0c;并进行进一步的处理和分析。 基…

Pytest插件pytest-django让Django测试更高效

在Django应用开发中&#xff0c;测试是确保应用质量的关键环节。然而&#xff0c;Django自带的测试框架并非总能满足开发者的需求&#xff0c;而Pytest插件 pytest-django 则为我们提供了更为灵活、强大的测试工具。本文将深入介绍 pytest-django 插件的基本用法和实际案例&…

ChatGPT给出的前端面试考点(html+css+JS)

ChatGPT给出的前端面试考点&#xff08;htmlcssJS&#xff09; HTML HTML是什么&#xff0c;它的主要作用是什么&#xff1f; 什么是DOCTYPE&#xff0c;为什么在HTML文档中使用它&#xff1f; HTML5相对于之前的HTML版本有哪些主要的新特性&#xff1f; 解释语义化HTML的概…

google网站流量怎么获取?

流量是一个综合性的指标&#xff0c;可以说做网站就是为了相关流量&#xff0c;一个网站流量都没有&#xff0c;那其实就跟摆饰品没什么区别 而想从谷歌这个搜索引擎里获取流量&#xff0c;一般都分为两种方式&#xff0c;一种是网站seo&#xff0c;另一种自然就是投广告&#…

智能反射面—流形优化

使用Manopt工具箱适合优化最小化问题&#xff0c;如果你的优化问题是最大化问题&#xff0c;那么需要将其转换为最小化问题然后使用Manopt工具箱求解。 具体安装过程 Matlab添加Manopt - 知乎 (zhihu.com) 优化问题 clc,clear; close all; srng(1);%rand seed N10; GR_num1e3…

一套可以替代人工的Cnc机床自动上下料机器人

Cnc机床自动上下料|整体解决方案 CNC机床自动上下料是指通过自动化设备和系统&#xff0c;实现CNC机床在加工过程中自动进行上下料操作。这种自动化系统通常包括自动送料机和卸料机&#xff0c;可以根据加工工件的尺寸和形状自动调整上下料的位置和角度&#xff0c;从而提高生产…

Spring Boot 优雅实现统一数据返回格式+统一异常处理+统一日志处理

在我们的项目开发中&#xff0c;我们都会对数据返回格式进行统一的处理&#xff0c;这样可以方便前端人员取数据&#xff0c;当然除了正常流程的数据返回格式需要统一以外&#xff0c;我们也需要对异常的情况进行统一的处理&#xff0c;以及项目必备的日志。 1. 统一返回格式 …

Unity 编辑器篇|(九)编辑器美化类( GUIStyle、GUISkin、EditorStyles) (全面总结 | 建议收藏)

目录 1. GUIStyle1.1 参数总览1.2 样式代码 2. GUISkin2.1 参数总览2.2 创建自定义Skin 3. EditorStyles2.1 参数总览1.2 反射获取所有EditorStyles 1. GUIStyle GUIStyle是一个用于定制GUI控件样式的类&#xff0c;它包含了控件的外观属性&#xff0c;如字体、颜色、背景等。…

visual studio的安装及scanf报错的解决

visual studio是一款很不错的c语言编译器 下载地址&#xff1a;官网 点击后跳转到以下界面 下滑后点击下载Vasual Sutdio&#xff0c;选择社区版即可 选择位置存放下载文件后&#xff0c;即可开始安装 安装时会稍微等一小会儿。然后会弹出这个窗口&#xff0c;我们选择安装位…

OpenGL DIR

Mesa简介-CSDN博客 Mesa, also called Mesa3D and The Mesa 3D Graphics Library, is an open source software implementation of OpenGL, Vulkan, and other graphics API specifications. Mesa translates these specifications to vendor-specific graphics ha…

网络安全 | 苹果承认 GPU 安全漏洞存在,iPhone 12、M2 MacBook Air 等受影响

1 月 17 日消息&#xff0c;苹果公司确认了近期出现的有关 Apple GPU 存在安全漏洞的报告&#xff0c;并承认 iPhone 12 和 M2 MacBook Air 受影响。 该漏洞可能使攻击者窃取由芯片处理的数据&#xff0c;包括与 ChatGPT 的对话内容等隐私信息。 安全研究人员发现&#xff0c;…

IntelliJ IDEA 中输出乱码解决

最近tomcat突然在控制台输出乱码&#xff0c;各种乱码问题&#xff0c;查阅大量的资料&#xff0c;最终得以解决. IDEA控制台输出乱码 问题一&#xff1a;idea中tomcat控制台输出乱码 运行本地的tomcat\bin\start.bat文件页面显示正常 在idea中显示乱码 解决&#xff1a; 根…

【C++】:STL序列式容器list源码剖析

一、list概述 总的来说&#xff1a;环形双向链表 特点&#xff1a; 底层是使用链表实现的&#xff0c;支持双向顺序访问 在list中任何位置进行插入和删除的速度都很快 不支持随机访问&#xff0c;为了访问一个元素&#xff0c;必须遍历整个容器 与其他容器相比&#xff0c;额外…