web-dev-qa-db-ja.com

メンバー関数のメモリアドレスを取得しますか?

C++でメンバー関数の絶対アドレスを取得するにはどうすればよいですか? (サンクにこれが必要です。)

メンバー関数ポインターは、絶対アドレスに変換できないため機能しません(void *)-タイプに関連するアドレスだけでなく、メモリ内の実際の関数のアドレスを知る必要があります。

31
user541686

MSVCのメンバー関数のアドレスを取得する構文が存在します(MSVC 2005 IMHOから開始)。しかし、それはかなりトリッキーです。さらに、取得したポインタを従来の方法で他のポインタ型にキャストすることは不可能です。それにもかかわらず、これを行う方法はありますが。

次に例を示します。

// class declaration
class MyClass
{
public:
    void Func();
    void Func(int a, int b);
};

// get the pointer to the member function
void (__thiscall MyClass::* pFunc)(int, int) = &MyClass::Func;

// naive pointer cast
void* pPtr = (void*) pFunc; // oops! this doesn't compile!

// another try
void* pPtr = reinterpret_cast<void*>(pFunc); // Damn! Still doesn't compile (why?!)

// tricky cast
void* pPtr = (void*&) pFunc; // this works

従来のキャストがreinterpret_castを使用しても機能しないという事実は、おそらくMSがこのキャストを強く推奨していないことを意味します。

それにもかかわらず、これを行うことができます。もちろん、これはすべて実装に依存します。サンクを実行するには、適切な呼び出し規約を知っている必要があります+適切なアセンブラースキルを持っている必要があります。

26
valdo

これを試して。何かを何かにキャストできるようにする必要があります

template<typename OUT, typename IN>
OUT ForceCast( IN in )
{
    union
    {
        IN  in;
        OUT out;
    }
    u = { in };

    return u.out;
};

その後

void* member_address = ForceCast<void*>(&SomeClass::SomeMethod);
4
HaPpY

デフォルトでは、C++メンバー関数は__thiscall呼び出し規約を使用します。メンバー関数を迂回させるには、トランポリンと迂回の両方がターゲット関数とまったく同じ呼び出し規約を持つ必要があります。残念ながら、VCコンパイラは__thiscallをサポートしていないため、正当な迂回およびトランポリン関数を作成する唯一の方法は、それらを「迂回」クラスのメンバーにすることです。

また、C++では、メンバー関数へのポインターの任意のポインターへの変換はサポートされていません。 未加工のポインターを取得するには、メンバー関数のアドレスを一時的なメンバー関数ポインターに移動してから、そのアドレスを取得して渡し、逆参照する必要があります。幸い、コンパイラーはコードを最適化して、余分なポインター操作を削除します。

microsoft Detourライブラリから。彼らはコードインジェクションを扱い、非仮想メンバー関数のアドレスを取得することについて議論します。もちろん、それはコンパイラ実装固有のものです。

ライブラリはここにあります http://research.Microsoft.com/en-us/downloads/d36340fb-4d3c-4ddd-bf5b-1db25d03713d/default.aspx

2
kreuzerkrieg