从可执行文件调用成员函数
Call member function from executable
我正在尝试在我拥有PDB文件的游戏服务器中执行一些功能。所有的修改都在我的DLL中进行编码。
I'm refering global functions using it pointer like this :
.cpp file
pXXX YYY = (pXXX) 0x00403B7F;
.h file
typedef <return_type_function>(*pXXX)(<args>);
extern pXXX YYY;
当我试图调用一个成员函数时,问题发生了。我读了一些关于引用成员函数是不同的。我在类1中使用的函数都可以工作,但是当我试图调用类2中的函数时,游戏服务器崩溃了。
为什么第一类的函数可以工作?也许是因为类1有构造函数,类2没有?所有函数都是公共的
有人能帮帮我吗?
c++非静态成员函数不仅仅是普通函数,因为:
- 要求隐式传递"this"参数
- 可能需要动态查找虚方法
同样在c++中,你不能声明"指向任何类的任何方法的指针,如果给定一个整数,则返回一个整数"。因此,理论上,指向方法的指针可以只是一个小整数,描述您感兴趣的方法是哪个(假设类是固定的,并且在编译时已知)。
实际上,对于g++(64位Linux)中的非虚方法,指向方法的指针似乎只是指向一个常规函数的指针,该函数在所有其他函数之前接受一个额外的指针参数,遵循标准的x86-64 abi。
例如在
类中struct Foo {
int k;
Foo(int k) : k(k) {}
int square(int x) { return k*x*x; }
int cube(int x) { return k*x*x*x; }
};
square
的代码为:
00000000004006d0 <_ZN3Foo6squareEi>:
4006d0: 8b 07 mov (%rdi),%eax ; get this->k in eax
4006d2: 0f af c6 imul %esi,%eax ; times x
4006d5: 0f af c6 imul %esi,%eax ; times x
4006d8: c3 retq
,其中%edi
是隐式的this
参数,%esi
是输入的x
参数,对于声明为
int meth(Foo *this_pointer, int x);
在g++中,方法指针最终实际上是指向函数代码的指针(在特定情况下,值是0x00000000004006d0
)。
当然,这只对64位Linux上的g++版本有效。在可移植的c++中,调用泛型类的泛型方法在概念上是不可能的,因为类的类型是方法签名的一部分,所以这方面的一切都是依赖于实现的。
我希望其他c++编译器也采用类似的方法(使用真实的代码地址使调用更有效),但您需要检查您的特定编译器/环境。
使用g++
的示例作为一个简单的例子,考虑以下代码#include <stdio.h>
struct MyClass {
int x;
MyClass(int x) : x(x) {
}
void dump(int y) {
printf("dump() called: x = %i, y = %in", x, y);
}
};
MyClass class1(1111);
MyClass class2(2222);
MyClass *getClass(int x) {
if (x == 1) return &class1;
if (x == 2) return &class2;
return NULL;
}
void (MyClass::*aptr)(int) = &MyClass::dump; // NEEDED
作为共享库与:
编译g++ -Wall -O3 -fPIC -shared mylib.cpp -o mylib.so
并考虑这个程序
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, const char *argv[]) {
void *p = dlopen("./prg.so", RTLD_LAZY);
printf("p = %pn", p);
if (p) {
void *(*geti)(int);
geti = (void *(*)(int)) dlsym(p, "_Z8getClassi");
void (*dump)(void *, int);
dump = (void (*)(void *, int)) dlsym(p, "_ZN7MyClass4dumpEi");
printf("geti = %pn", geti);
printf("dump = %pn", dump);
if (geti) {
for (int i=0; i<4; i++) {
void *q = geti(i);
printf("geti(%i) = %pn", i, q);
if (q && dump) {
printf(" calling dump on the instance:n");
dump(q, 33);
}
}
}
}
return 0;
}
通常作为独立的可执行C程序(gcc,而不是g++)编译。
程序将加载c++库并在两个实例上调用dump
方法,将它们声明为接受额外的this
参数的普通C函数。但是要注意
- 所有这些都是高度不可移植的,并且可能在更复杂的情况下即使使用g++/gcc也无法工作。似乎混合g++和clang++也可以工作,但对于这个简单的例子来说,这可能是一个巧合。
- 你需要知道你希望调用方法的对象的实例的地址…这里我使用了
getClass
函数 - 您需要知道要调用的函数的混乱名称
- 可能不是所有类的方法都被暴露;例如,我必须在这个玩具测试中强制它,否则
dump
根本不存在于共享库中(参见"NEEDED"注释)。
总结起来…你真的真的想弄得这么脏吗?
- 如何使用指针传递给函数的数组中对象的函数成员
- c++构造函数成员初始化:传递参数
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何在C++通过公共函数访问私有函数成员?
- 解释了构造函数成员初始化列表
- 调用std::函数成员时内存损坏
- 是否可以为模板类的模板函数成员设置别名?
- 捕获 lambda 函数C++成员变量
- 构造函数成员初始值设定项跨成员列出,安全吗?
- 获取与在模板参数中传递的函数成员类型相同的类
- 如何从公共函数成员访问地图私有成员
- C 构造函数成员分配优化
- 使用命名空间进行函数成员定义
- 函数成员作为 CUDA 内核的参数
- 模板基类函数成员的别名
- 函数成员中用于void和继承的enable_if
- 头文件中是否定义了一个很长的Class函数成员
- 类内/构造函数成员初始化
- 使用指向部分专用函数成员的指针自动填充向量
- 指向函数成员的指针