我想通过asm块调用C ++成员函数。编译器是MSVC ++(VS2008),可移植性不是问题。我必须为嵌入式系统构建一个远程/ RMI类型机制。客户端发送对象名称,方法名称,参数(序列化),我需要将方法调用到适当的对象。我可以从PDB文件中获取的类型信息。我需要编写一个通用的Invoke函数。我坚持如何调用一个以对象作为参数的成员函数。 Specifially。我无法获得复制ctor的指针。任何想法。
PS:下面的代码为C :: funcRef
编译并正确运行#include <stdio.h>
struct Point
{
int x;
int y;
Point()
{
x = 10;
y =10;
}
Point(const Point& p)
{
x = p.x;
y = p.y;
}
virtual ~Point()
{
}
};
class C
{
public:
void funcRef(Point& p)
{
printf("C::funcRef\n x= %d, y =%d\n", p.x, p.y);
}
void funcObj(Point p)
{
printf("C::funcObj\nx = %d y = %d\n", p.x, p.y);
}
};
void main()
{
C* c = new C;
Point p;
//c->funcRef(p);
// this works
__asm
{
lea eax, p;
push eax;
mov ecx, c;
call [C::funcRef];
}
// c->funcObj(p);
__asm
{
sub esp, 12; // make room for sizeof(Point)
mov ecx, esp;
lea eax, p;
push eax;
// how to call copy ctor here
mov ecx, c;
call [C::funcObj];
}
}
答案 0 :(得分:2)
由于复制构造函数是非虚拟的,因此您只需按名称查找并调用它即可。了解编译器如何破坏复制构造函数,以及如何按名称解析符号(您可能对GetProcAddress感兴趣。)
这是一个linux示例,但请注意它对visual studio使用不同的调用约定:
#include <stdio.h>
#include <dlfcn.h>
struct Point
{
int x;
int y;
Point()
{
printf("Default constructing point @%p\n", this);
x = 10;
y = 10;
}
Point(const Point& p) __attribute__((used, visibility("default")))
{
printf("Copy constructing point @%p from point @%p\n", this, &p);
x = p.x;
y = p.y;
}
virtual ~Point()
{
printf("Point @%p destroyed\n", this);
}
};
class C
{
public:
void funcRef(Point& p)
{
printf("C::funcRef\n x= %d, y =%d\n", p.x, p.y);
}
void funcObj(Point p)
{
printf("C::funcObj p = %p, x = %d, y = %d\n", &p, p.x, p.y);
}
};
typedef void (C::*FRef)(Point&);
typedef void (C::*FObj)(Point);
int main()
{
C* c = new C;
Point p;
FRef _fref = &C::funcRef;
FObj _fobj = &C::funcObj;
// c->funcObj(p);
void* self = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
printf("Module handle for self is %p\n", self);
// mangled name of Point::Point(const Point&)
void* constructor = dlsym(self, "_ZN5PointC1ERKS_");
printf("Constructor address is %p\n", constructor);
void* dummy;
__asm__ __volatile__ (
"sub esp, 32\n\t"
"mov [esp+4], %[p] # argument to copy constructor\n\t"
"lea eax, [esp+20]\n\t"
"mov [esp], eax # this pointer\n\t"
"call %[constructor] # construct instance at [esp+20]\n\t"
"lea eax, [esp+20]\n\t"
"mov [esp+4], eax # argument to function\n\t"
"mov [esp], %[c] # this pointer\n\t"
"call %[fobj]\n\t"
"lea eax, [esp+20]\n\t"
"mov [esp], eax # this pointer\n\t"
"mov eax, [eax] # vtable\n\t"
"call [eax] # destructor\n\t"
"add esp, 32 # free rest of stack\n\t"
: "=a" (dummy), "=c" (dummy)
: [p] "a" (&p), [c] "S" (&c), [fobj] "D" ((void*)_fobj), [constructor] "c" (constructor)
: "edx");
return 0;
}
试运行:
Default constructing point @0xffc145e4
Module handle for self is 0xf77fb900
Constructor address is 0x8048c02
Copy constructing point @0xffc145b4 from point @0xffc145e4
C::funcObj p = 0xffc145b4, x = 10, y = 10
Point @0xffc145b4 destroyed
Point @0xffc145e4 destroyed
答案 1 :(得分:0)
Jester提供了解决此问题的一种方法。我找到了另一种特定于MSVC的方法。我们可以使用 FUNCDNAME 来获取副本ctor的装饰名称,然后获取procadders。这是我修改过的代码
#include <stdio.h>
struct Point
{
static char* pointCopyCtorName;
int x;
int y;
Point()
{
if ( !pointCopyCtorName )
{
// force copy ctor
Point(*this);
}
x = 10;
y =10;
}
__declspec(dllexport) Point(const Point& p)
{
if ( !pointCopyCtorName )
pointCopyCtorName = __FUNCDNAME__;
if ( this != &p )
{
x = p.x;
y = p.y;
}
}
virtual ~Point()
{
}
};
char* Point::pointCopyCtorName = NULL;
class C
{
public:
void funcRef(Point& p)
{
printf("C::funcRef\n x= %d, y =%d\n", p.x, p.y);
}
void funcObj(Point p)
{
printf("C::funcObj\nx = %d y = %d\n", p.x, p.y);
}
};
HMODULE GetCurrentModule()
{
HMODULE hMod = NULL;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR) "GetCurrrentModule", &hMod);
return hMod;
}
void main()
{
C* c = new C;
Point p;
HMODULE hMod = GetCurrentModule();
if ( !hMod )
return;
FARPROC pPointCopyCtor = GetProcAddress(hMod, p.pointCopyCtorName);
if ( !pPointCopyCtor )
return;
//c->funcRef(p);
// this works
__asm
{
lea eax, p;
push eax;
mov ecx, c;
call [C::funcRef];
}
// c->funcObj(p);
__asm
{
sub esp, 12;
mov ecx, esp;
lea eax, p;
push eax;
call pPointCopyCtor;
mov ecx, c;
call [C::funcObj];
}
}