如何在没有头文件的情况下调用动态库的类成员函数
- 编写一个不存在虚函数的类
- 测试代码
- _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 *);
调用也就和普通函数一致。
注意:以上不涉及虚函数时可正常使用,当存在虚函数时,会存在虚函数表,无法确定被调用函数真正的地址。