使用asm的引用参数调用C ++成员函数

时间:2013-01-15 20:45:13

标签: c++ assembly x86

我想通过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];

   }

}

2 个答案:

答案 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];
   }

}