如何在没有头文件的情况下调用动态库的类的私有成员函数

如何在没有头文件的情况下调用动态库的类成员函数

        • 编写一个不存在虚函数的类
        • 测试代码
      • _ZN6CClass4showEv如何获取
        • 调用

源代码 https://github.com/TonyBeen/study/tree/master/dlopen

编写一个不存在虚函数的类
// class.h
#pragma onceclass CClass
{
public:CClass();~CClass();private:void show();private:char _buffer[64];
};// class.cc
#include "class.h"
#include <stdio.h>
#include <string.h>CClass::CClass()
{size_t size = sizeof(_buffer);memset(_buffer, '1', size);_buffer[size - 1] = '\0';
}CClass::~CClass()
{
}void CClass::show()
{printf("%s\n", _buffer);
}extern "C" {CClass* createClass() {return new CClass();}void destroyClass(CClass* obj) {delete obj;}
}

编译指令: g++ -shared -fPIC -o libmyclass.so class.cc -O2

测试代码
// test_class.cc
#include <iostream>
#include <dlfcn.h>typedef void* (*CreateFunction)();
typedef void (*DestroyFunction)(void *);typedef void (*DoShow)(void *);int main(int argc, char **argv)
{void* handle = dlopen("./libmyclass.so", RTLD_LAZY);if (!handle) {std::cerr << "Error opening shared library: " << dlerror() << std::endl;return 1;}// 获取创建和销毁函数的指针CreateFunction createFunc = (CreateFunction)dlsym(handle, "createClass");if (!createFunc) {std::cerr << "Error loading create function: " << dlerror() << std::endl;dlclose(handle);return 1;}DestroyFunction destroyFunc = (DestroyFunction)dlsym(handle, "destroyClass");if (!destroyFunc) {std::cerr << "Error loading destroy function: " << dlerror() << std::endl;dlclose(handle);return 1;}void* obj = createFunc();if (!obj) {std::cerr << "Error creating MyClass instance" << std::endl;dlclose(handle);return 1;}DoShow pFnShow = (DoShow)dlsym(handle, "_ZN6CClass4showEv");pFnShow(obj);destroyFunc(obj);// 关闭共享库dlclose(handle);return 0;
}

编译指令: g++ test_class.cc -o test_class -O2 -ldl

输出内容: 111111111111111111111111111111111111111111111111111111111111111

_ZN6CClass4showEv如何获取

获取方式有三种:
1、nm libmyclass.so

0000000000004058 b completed.7658
00000000000011c0 T createClass
w __cxa_finalize@@GLIBC_2.2.5
00000000000010a0 t deregister_tm_clones
0000000000001200 T destroyClass
0000000000001130 t __do_global_dtors_aux
0000000000003df8 d __do_global_dtors_aux_fini_array_entry
0000000000004048 d __dso_handle
0000000000004050 d DW.ref.__gxx_personality_v0
0000000000003e00 d _DYNAMIC
0000000000001224 t _fini
0000000000001170 t frame_dummy
0000000000003df0 d __frame_dummy_init_array_entry
0000000000002158 r FRAME_END
0000000000004000 d GLOBAL_OFFSET_TABLE
w gmon_start
0000000000002010 r __GNU_EH_FRAME_HDR
U __gxx_personality_v0@@CXXABI_1.3
0000000000001000 t _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U puts@@GLIBC_2.2.5
00000000000010e0 t register_tm_clones
0000000000004058 d TMC_END
U _Unwind_Resume@@GCC_3.0
U _ZdlPvm@@CXXABI_1.3.9
00000000000011b0 T _ZN6CClass4showEv
0000000000001180 T _ZN6CClassC1Ev
0000000000001180 T _ZN6CClassC2Ev
00000000000011a0 T _ZN6CClassD1Ev
00000000000011a0 T _ZN6CClassD2Ev
U _Znwm@@GLIBCXX_3.4

2、readelf -s libmyclass.so

Symbol table ‘.dynsym’ contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Znwm@GLIBCXX_3.4 (3)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZdlPvm@CXXABI_1.3.9 (4)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3 (5)
6: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@GCC_3.0 (6)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND gmon_start
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
10: 0000000000001200 34 FUNC GLOBAL DEFAULT 12 destroyClass
11: 00000000000011c0 61 FUNC GLOBAL DEFAULT 12 createClass
12: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC2Ev
13: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD1Ev
14: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD2Ev
15: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC1Ev
16: 00000000000011b0 5 FUNC GLOBAL DEFAULT 12 _ZN6CClass4showEv

Symbol table ‘.symtab’ contains 62 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000238 0 SECTION LOCAL DEFAULT 1
2: 0000000000000260 0 SECTION LOCAL DEFAULT 2
3: 00000000000002a0 0 SECTION LOCAL DEFAULT 3
4: 0000000000000438 0 SECTION LOCAL DEFAULT 4
5: 000000000000058a 0 SECTION LOCAL DEFAULT 5
6: 00000000000005b0 0 SECTION LOCAL DEFAULT 6
7: 0000000000000630 0 SECTION LOCAL DEFAULT 7
8: 00000000000006f0 0 SECTION LOCAL DEFAULT 8
9: 0000000000001000 0 SECTION LOCAL DEFAULT 9
10: 0000000000001020 0 SECTION LOCAL DEFAULT 10
11: 0000000000001090 0 SECTION LOCAL DEFAULT 11
12: 00000000000010a0 0 SECTION LOCAL DEFAULT 12
13: 0000000000001224 0 SECTION LOCAL DEFAULT 13
14: 0000000000002000 0 SECTION LOCAL DEFAULT 14
15: 0000000000002010 0 SECTION LOCAL DEFAULT 15
16: 0000000000002058 0 SECTION LOCAL DEFAULT 16
17: 000000000000215c 0 SECTION LOCAL DEFAULT 17
18: 0000000000003df0 0 SECTION LOCAL DEFAULT 18
19: 0000000000003df8 0 SECTION LOCAL DEFAULT 19
20: 0000000000003e00 0 SECTION LOCAL DEFAULT 20
21: 0000000000003fe0 0 SECTION LOCAL DEFAULT 21
22: 0000000000004000 0 SECTION LOCAL DEFAULT 22
23: 0000000000004048 0 SECTION LOCAL DEFAULT 23
24: 0000000000004058 0 SECTION LOCAL DEFAULT 24
25: 0000000000000000 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
27: 00000000000010a0 0 FUNC LOCAL DEFAULT 12 deregister_tm_clones
28: 00000000000010e0 0 FUNC LOCAL DEFAULT 12 register_tm_clones
29: 0000000000001130 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
30: 0000000000004058 1 OBJECT LOCAL DEFAULT 24 completed.7658
31: 0000000000003df8 0 OBJECT LOCAL DEFAULT 19 __do_global_dtors_aux_fin
32: 0000000000001170 0 FUNC LOCAL DEFAULT 12 frame_dummy
33: 0000000000003df0 0 OBJECT LOCAL DEFAULT 18 _frame_dummy_init_array
34: 0000000000000000 0 FILE LOCAL DEFAULT ABS class.cc
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
36: 0000000000002158 0 OBJECT LOCAL DEFAULT 16 FRAME_END
37: 0000000000000000 0 FILE LOCAL DEFAULT ABS
38: 0000000000002010 0 NOTYPE LOCAL DEFAULT 15 __GNU_EH_FRAME_HDR
39: 0000000000004048 0 OBJECT LOCAL DEFAULT 23 __dso_handle
40: 0000000000004050 8 OBJECT LOCAL DEFAULT 23 DW.ref._gxx_personality
41: 0000000000001224 0 FUNC LOCAL DEFAULT 13 _fini
42: 0000000000001000 0 FUNC LOCAL DEFAULT 9 _init
43: 0000000000003e00 0 OBJECT LOCAL DEFAULT 20 _DYNAMIC
44: 0000000000004058 0 OBJECT LOCAL DEFAULT 23 TMC_END
45: 0000000000004000 0 OBJECT LOCAL DEFAULT 22 GLOBAL_OFFSET_TABLE
46: 00000000000011c0 61 FUNC GLOBAL DEFAULT 12 createClass
47: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2
48: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC2Ev
49: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD1Ev
50: 00000000000011b0 5 FUNC GLOBAL DEFAULT 12 _ZN6CClass4showEv
51: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD2Ev
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Znwm@@GLIBCXX_3.4
53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZdlPvm@@CXXABI_1.3.9
54: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC1Ev
55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
56: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@@CXX
57: 0000000000001200 34 FUNC GLOBAL DEFAULT 12 destroyClass
58: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@@GCC_3.0
60: 0000000000000000 0 NOTYPE WEAK DEFAULT UND gmon_start
61: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable

3、objdump -x libmyclass.so
此处输出过多, 不在展示

通过以上方式均可获取到符号表
只需要找到_ZN6CClass4showEv即可

调用

普通函数的调用方式为直接调用,如createClass。
类的成员函数调用:

class T
{
public:void print();
};T t = new T();
auto pFnPrint = &T::print;
(t->*pFnPrint)();

然这么写在编译时确实没问题,但是动态加载的情况下又没有类的头文件,则无法这么写,因为无法确定函数的地址。
所以需要使用dlsym获取到地址,但是g++在编译时会对函数名称进行修改,如上所示。故传递时需要传修改后的名字。
另一方面,类的成员函数即使在书写时无参,那么编译后其实也存在参数的,即类的this。
所以在生命函数时将其声明为typedef void (*DoShow)(void *);调用也就和普通函数一致。

注意:以上不涉及虚函数时可正常使用,当存在虚函数时,会存在虚函数表,无法确定被调用函数真正的地址。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Leetcode每日一题】 综合练习 - 电话号码的字母组合(难度⭐⭐)(75)

1. 题目解析 题目链接&#xff1a;电话号码的字母组合 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法设计思路 在解决这类问题时&#xff0c;我们需要认识到每个位置上的数字对应的字符集合是相互独立的&#…

什么是翘尾因素

在有关CPI 的分析文章和新闻稿件中&#xff0c;经常会出现“翘尾因素”或“翘尾影响” 等词汇&#xff0c;这是分析同比价格指数变动幅度时所特有的概念。那么什么是“翘尾因素” 或“翘尾影响”呢&#xff1f; 一、什么是翘尾因素 “翘尾因素”是指上年价格上涨&#xff08;…

使用scrollIntoView滚动元素到可视区域

1. 实现效果 点击顶部标签栏&#xff0c;让对应的内容出现在可视区域&#xff1a; 2. scrollIntoView () scrollIntoView 是一个内置的 JavaScript 方法&#xff0c;用于将元素滚动到视口可见的位置。它通常用于用户界面中&#xff0c;以便用户能轻松看到特定的元素。此方…

perf 中的 cpu-cycles event 介绍

perf 中的 cpu-cycles event 介绍 cycles简介 cycles事件记录处理器核心执行的时钟周期数。每个时钟周期代表处理器内部时钟振荡器的一个周期。这个事件通常用于衡量处理器的执行速度&#xff0c;因为它直接反映了指令执行所需的时间。一个较高的cycles计数可能意味着代码执行…

JavaScript中指定大小分割数组的一种实现

今天分享一个使用JavaScript分割数组为多个自数组的方法实现。我使用它的场景如下&#xff1a; 给定一个数组 arr 和指定大小 fixed&#xff1a; const arr [{id: 1,name: name1},{id: 2,name: name2},{id: 3,name: name3},{id: 4,name: name4},{id: 5,name: name5},{id: 6,…

2024版本idea集成SpringBoot + Ai 手写一个chatgpt 【推荐】

题目&#xff1a;SpringBoot OpenAi 在这里获取key和url&#xff1a;获取免费key base-url为这两个&#xff1a; 话不多说直接来&#xff01; 一、简介 Spring AI 是 AI 工程的应用框架。其目标是将 Spring 生态系统设计原则&#xff08;如可移植性和模块化设计&#xff…

暗区突围pc资格 暗区突围pc端测试资格获取

《暗区突围》的诞生&#xff0c;仿佛在游戏界投下了一枚深水炸弹&#xff0c;它不仅仅是射击游戏的新标杆&#xff0c;更是对玩家策略思维、生存直觉与团队协作能力的一次全面考验。在这个精心构建的虚拟战场中&#xff0c;每一次踏入暗区&#xff0c;都是对未知的探索&#xf…

【练习4】

1.两数之和 暴力&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {int n nums.size();vector<int> res(2, -1); // 初始化结果为-1for (int i 0; i < n; i) {int temp nums[i];for (int j i 1; j <…

Python 技巧:满意的逗号放置

当你在 Python 中添加或删除列表、字典或集合中的项目时&#xff0c;记住总是将所有行结尾加一个逗号。这是一个非常有用的技巧&#xff0c;可以帮助你避免一些常见的问题。 不确定我所说的什么&#xff1f;让我给你一个快速示例。假设你在代码中有一個名单列表&#xff1a; …

银行家算法简易实现

这里写目录标题 实验要求内容代码main.cppmyfunc.hmyfunc.cpp 运行结果与分析 实验要求 程序可以针对不同进程的请求进行判断&#xff0c;并决定是否满足其需求。算法程序需要设计合理的数据结构&#xff0c;对资源情况、进程相关数据进行存储。 内容 随机生成数据, 并校验数据…

做视频号小店,怎么找达人合作?这里有详细讲解

大家好&#xff0c;我是电商笨笨熊 做视频号小店是没有自然流量的&#xff0c;这点刚入驻的新玩家还不清楚&#xff1b; 因此很多老电商玩家们还想着继续拿其他平台动销自然流的玩法去做视频号&#xff1b; 只能说这种方式在视频号是完全行不通的&#xff0c;当下想要推广售…

设计模式2——原则篇:依赖倒转原则、单一职责原则、合成|聚合复用原则、开放-封闭原则、迪米特法则、里氏代换原则

设计模式2——设计原则篇 目录 一、依赖倒转原则 二、单一职责原则&#xff08;SRP&#xff09; 三、合成|聚合复用原则&#xff08;CARP&#xff09; 四、开放-封闭原则 五、迪米特法则&#xff08;LoD&#xff09; 六、里氏代换原则 七、接口隔离原则 八、总结 一、依赖…

Python-VBA函数之旅-setattr函数

目录 一、setattr函数的常见应用场景 二、setattr函数使用注意事项 三、如何用好setattr函数&#xff1f; 1、setattr函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://blog.csdn.net/ygb_1024?…

宏集Panorama SCADA软件获BACnet BTL认证

Panorama 获得BACnet BTL认证 建筑物的组件&#xff08;空调系统、照明传感器等&#xff09;能否使用共同通讯协议&#xff1f;这正是标准化 BACnet协议&#xff08;Building Automation and Control Networks&#xff09;所提供的功能。该协议旨在实现建筑物中各种设备和系统…

【TS】入门

创建项目 vscode自动编译ts 生成配置文件 tsc --init 然后发现终端也改变了&#xff1a;

SOCKET编程(3):相关结构体与函数

相关结构体与函数 sockaddr、sockaddr_in结构体 sockaddr和sockaddr_in详解 struct sockaddr共16字节&#xff0c;协议族(family)占2字节&#xff0c;IP地址和端口号在sa_data字符数组中 /* Structure describing a generic socket address. */ struct sockaddr {__SOCKADDR…

抓大鹅教程电脑端秒通关……

大家好&#xff0c;我是小黄。 最近抓大鹅小程序游戏很火&#xff0c;抓大鹅小游戏是由青岛蓝飞互娱科技股份有限公司开发并推出的一款休闲益智类三消游戏。在游戏中&#xff0c;玩家需要在特定的“购物篮子”背景下&#xff0c;找到三个相同的物品并将其消除。游戏的玩法简单…

社工库信息查询

此网站需要注册账号&#xff0c;新用户注册送3点券&#xff0c;每日签到可获得1.5点券。也可通过充值来查 我这里有方法可以利用缺陷来无限获取点券查人

Python 实战之量化交易

1. Python 实战之量化交易 2..Python量化交易实战-04.量化交易系统架构的设计 Python量化交易实战-04.量化交易系统架构的设计 - 知乎 3.Python量化交易实战-06.通过PythonAPI获取股票数据 Python量化交易实战-06.通过PythonAPI获取股票数据 - 知乎 3.Python量化交易实战…

程序员的归宿。。

大家好&#xff0c;我是瑶琴呀。 相信每个进入职场的人都考虑过自己的职业生涯规划&#xff0c;在不同的年龄段可能面临不同挑战&#xff0c;这点对于 35 的人应该更为感同身受。 对于程序员来说&#xff0c;大部分人的职业道路主要是下面三种&#xff1a;第一条&#xff0c;…