2013-01-15 76 views
5

我想通過asm塊調用C++成員函數。編譯器是MSVC++(VS2008),可移植性不是問題。我必須爲嵌入式系統構建一個遠程/ RMI類型的機制。客戶端發送對象名稱,方法名稱,參數(序列化),我需要調用該方法適當的對象。我可以從PDB文件中獲得的類型信息。我需要編寫一個通用的Invoke函數。我被困在如何調用一個將對象作爲參數的成員函數。 Specifially。我無法獲得指向複製ctor的指針。任何想法。從asm調用引用參數的C++成員函數

PS:以下編譯代碼並正確對C ::函數引用

#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

這裏的人們:http://www.asmcommunity.net/board/index.php?topic=17897.0似乎認爲你不能拷貝構造函數的地址。 – us2012

回答

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 
+0

謝謝。這對我有用。 – Charvak

0

小丑提供解決這一問題的方法之一。我發現了另一種特定於MSVC的方式。我們可以使用FUNCDNAME來獲取copy 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]; 
    } 

}