gpt4 book ai didi

c++ - 从可执行文件中调用成员函数

转载 作者:行者123 更新时间:2023-11-30 02:37:21 25 4
gpt4 key购买 nike

我正在尝试在具有 PDB 文件的游戏服务器中实现一些功能。所有修改都编码在我 Hook 的 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;

当我试图调用一个成员函数时,问题发生了。我读到一些关于引用成员函数不同的内容。我在 Class 1 中使用的函数都有效,但是当我尝试调用 Class 2 中的函数时,游戏服务器崩溃了。

为什么第 1 类中的功能有效?也许是因为 Class 1 有构造函数 Class 2 没有?所有功能都是公开的。

有人可以帮助我吗?谢谢,对不起我的英语。

最佳答案

C++ 非静态成员函数不仅仅是一个常规函数,因为:

  • 需要隐式传递的“this”参数
  • 可能需要动态查找虚拟方法

同样在 C++ 中,您不能声明“指向给定整数返回整数的任何类的任何方法的指针”。因此,理论上指向方法的指针可能只是一个小整数,描述了您感兴趣的方法(假设该类在编译时是固定的和已知的)。

但是在实践中,对于 g++(Linux 64 位)中的非虚拟方法,指向方法的指针似乎只是指向常规函数的指针,该函数在所有其他函数之前接受额外的指针参数,遵循标准 x86-64阿比。

例如在类里面

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 参数和代码对于声明为

的 C 函数是相同的
int meth(Foo *this_pointer, int x);

对于 g++,方法指针最终实际上是指向函数代码的指针(在特定情况下,该值是 0x00000000004006d0)。

当然请注意,这仅适用于 Linux 64 位上的此版本的 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 = %i\n", 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 = %p\n", 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 = %p\n", geti);
printf("dump = %p\n", dump);
if (geti) {
for (int i=0; i<4; i++) {
void *q = geti(i);
printf("geti(%i) = %p\n", i, q);
if (q && dump) {
printf(" calling dump on the instance:\n");
dump(q, 33);
}
}
}
}
return 0;
}

正常编译为独立的可执行 C 程序(gcc,而非 g++)。

该程序将加载 C++ 库,并将在两个实例上调用 dump 方法,将它们声明为接受额外 this 参数的普通 C 函数。但是请注意

  1. 所有这些都是高度不可移植的,并且可能它在更复杂的情况下即使使用 g++/gcc 也不起作用。似乎也可以混合使用 g++ 和 clang++,但这对于这个简单的案例来说可能是巧合。
  2. 您需要知道您希望调用其方法的对象实例的地址...这里我使用了一个getClass函数
  3. 您需要知道要调用的函数的名称
  4. 可能不是类的所有方法都公开;例如,我不得不在这个玩具测试中强制使用它,否则 dump 根本不存在于共享库中(请参阅“需要”评论)。

总而言之...您真的确定要弄脏它吗?

关于c++ - 从可执行文件中调用成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31723765/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com