#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <Windows.h>
/*
mingw (tested with gcc4.7.2, gcc4.8.1)
g++ cpp105-628.cpp -o cpp105-628-gcc
vc (tested with vc2008,vc2010,vc2013)
cl /c cpp105-628.cpp
link /INCREMENTAL:NO cpp105-628.obj
*/
/*****************************************************************************************/
#ifdef __GNUC__
#define CALLMEMBERFUNC_DECL_1 __attribute__ ((__optimize__(0,"omit-frame-pointer")))
#define CALLMEMBERFUNC_DECL_2
#else //_MSC_VER
#define CALLMEMBERFUNC_DECL_1
#define CALLMEMBERFUNC_DECL_2 __declspec(naked)
#endif
#pragma pack(push,1)
template<class T>
struct CALLMEMBERFUNC
{
typedef void(*CALLMEMBERFUNC_FUNC)();
typedef void(*BYPASSFUNC)(T* This, void* /*return address*/, ...);
T* This;
BYPASSFUNC classfunc;
char funcdata[40];
template<class F>
CALLMEMBERFUNC(T* cls, F clsfunc)
{
memcpy((void*)funcdata, (void*)CallMemberFunc, sizeof(funcdata));
set(cls, clsfunc);
}
void *operator new(size_t size)
{
return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
void operator delete(void* p)
{
VirtualFree(p, 0, MEM_RELEASE);
}
template<class F>
void set(T* cls, F clsfunc)
{
This = cls;
classfunc = (BYPASSFUNC)clsfunc;
}
CALLMEMBERFUNC_FUNC getfunc()
{
return reinterpret_cast<CALLMEMBERFUNC_FUNC>(&funcdata[0]);
}
static void CallMemberFunc() CALLMEMBERFUNC_DECL_1;
static const int func_offset;
static const int funcdata_offset;
};
#pragma pack(pop)
#ifdef __GNUC__
template<class T> const int CALLMEMBERFUNC<T>::func_offset = offsetof(CALLMEMBERFUNC<T>,classfunc);
template<class T> const int CALLMEMBERFUNC<T>::funcdata_offset = offsetof(CALLMEMBERFUNC<T>,funcdata);
#else //_MSC_VER
//#define FIELD_OFFSET(type, field) ((int)(int*)&(((type *)0)->field))
template<class T> const int CALLMEMBERFUNC<T>::func_offset = FIELD_OFFSET(CALLMEMBERFUNC,classfunc);
template<class T> const int CALLMEMBERFUNC<T>::funcdata_offset = FIELD_OFFSET(CALLMEMBERFUNC,funcdata);
#endif
template<class T>
CALLMEMBERFUNC_DECL_2 void CALLMEMBERFUNC<T>::CallMemberFunc()
{
#ifdef __GNUC__
__asm__("call 1f\n\t"
"1: popl %%eax\n"
"subl $5,%%eax\n"
"subl %0,%%eax\n"
"movl (%%eax), %%ecx\n"
"add %1, %%eax\n"
"mov (%%eax), %%eax\n"
"push %%ecx\n"
"call *%%eax\n"
"addl $4,%%esp\n"
"ret"
:
: "i"(funcdata_offset), "i"(func_offset)
);
#else //_MSC_VER
_asm{
call CallMemberFunc_check_pc
CallMemberFunc_check_pc:
pop eax
sub eax,5
sub eax,funcdata_offset
mov ecx,[eax]
add eax,func_offset
mov eax, [eax]
push ecx
call eax
add esp,4
ret
}
#endif
}
/*****************************************************************************************/
extern "C" typedef int(*FUNC_ADD)(int);
extern "C" int add(FUNC_ADD func, int x, int y)
{
return func(x) + func(y);
}
extern "C" typedef void(*FUNC_PRINT)(const char*, int, int);
extern "C" void print(FUNC_PRINT func, int x, int y)
{
func("print x:%d, y:%d\n", x, y);
}
class TEST
{
int a;
CALLMEMBERFUNC<TEST> *cmf_add, *cmf_print;
public:
TEST(int x) : a(x)
{
cmf_add = new CALLMEMBERFUNC<TEST>(this, cmf_func_add);
cmf_print = new CALLMEMBERFUNC<TEST>(this, cmf_func_print);
}
~TEST()
{
delete cmf_add;
delete cmf_print;
}
int func_add(int x)
{
return a * x;
}
static int cmf_func_add(TEST* This, void*, int x)
{
return This->func_add(x);
}
void func_print(const char* fmt, int x, int y)
{
printf(fmt, x * a, y * a);
}
static void cmf_func_print(TEST* This, void*, const char* fmt, int x, int y)
{
This->func_print(fmt, x, y);
}
operator FUNC_ADD()
{
return reinterpret_cast<FUNC_ADD>(cmf_add->getfunc());
}
operator FUNC_PRINT()
{
return reinterpret_cast<FUNC_PRINT>(cmf_print->getfunc());
}
};
int main()
{
TEST t(100);
printf("add %d\n", add(t, 1, 2));
print(t, 3, 4);
return 0;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdHJpbmcuaD4KI2luY2x1ZGUgPHN0ZGRlZi5oPgoKI2luY2x1ZGUgPFdpbmRvd3MuaD4KCi8qCgltaW5ndyAodGVzdGVkIHdpdGggZ2NjNC43LjIsIGdjYzQuOC4xKQoJCWcrKyBjcHAxMDUtNjI4LmNwcCAtbyBjcHAxMDUtNjI4LWdjYwoKCXZjICAodGVzdGVkIHdpdGggdmMyMDA4LHZjMjAxMCx2YzIwMTMpCgkJY2wgL2MgY3BwMTA1LTYyOC5jcHAKCQlsaW5rIC9JTkNSRU1FTlRBTDpOTyBjcHAxMDUtNjI4Lm9iagoqLwoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKI2lmZGVmIF9fR05VQ19fCgkjZGVmaW5lIENBTExNRU1CRVJGVU5DX0RFQ0xfMSBfX2F0dHJpYnV0ZV9fICgoX19vcHRpbWl6ZV9fKDAsIm9taXQtZnJhbWUtcG9pbnRlciIpKSkKCSNkZWZpbmUgQ0FMTE1FTUJFUkZVTkNfREVDTF8yCiNlbHNlCS8vX01TQ19WRVIKCSNkZWZpbmUgQ0FMTE1FTUJFUkZVTkNfREVDTF8xCgkjZGVmaW5lIENBTExNRU1CRVJGVU5DX0RFQ0xfMiBfX2RlY2xzcGVjKG5ha2VkKQojZW5kaWYKCiNwcmFnbWEgcGFjayhwdXNoLDEpCnRlbXBsYXRlPGNsYXNzIFQ+CnN0cnVjdCBDQUxMTUVNQkVSRlVOQwp7Cgl0eXBlZGVmIHZvaWQoKkNBTExNRU1CRVJGVU5DX0ZVTkMpKCk7Cgl0eXBlZGVmIHZvaWQoKkJZUEFTU0ZVTkMpKFQqIFRoaXMsIHZvaWQqIC8qcmV0dXJuIGFkZHJlc3MqLywgLi4uKTsKCglUKiBUaGlzOwoJQllQQVNTRlVOQyBjbGFzc2Z1bmM7CgljaGFyIGZ1bmNkYXRhWzQwXTsKCgl0ZW1wbGF0ZTxjbGFzcyBGPgoJQ0FMTE1FTUJFUkZVTkMoVCogY2xzLCBGIGNsc2Z1bmMpCgl7CgkJbWVtY3B5KCh2b2lkKilmdW5jZGF0YSwgKHZvaWQqKUNhbGxNZW1iZXJGdW5jLCBzaXplb2YoZnVuY2RhdGEpKTsKCQlzZXQoY2xzLCBjbHNmdW5jKTsKCX0KCgl2b2lkICpvcGVyYXRvciBuZXcoc2l6ZV90IHNpemUpCgl7CgkJcmV0dXJuIFZpcnR1YWxBbGxvYyhOVUxMLCBzaXplLCBNRU1fQ09NTUlULCBQQUdFX0VYRUNVVEVfUkVBRFdSSVRFKTsKCX0KCgl2b2lkIG9wZXJhdG9yIGRlbGV0ZSh2b2lkKiBwKQoJewoJCVZpcnR1YWxGcmVlKHAsIDAsIE1FTV9SRUxFQVNFKTsKCX0KCgl0ZW1wbGF0ZTxjbGFzcyBGPgoJdm9pZCBzZXQoVCogY2xzLCBGIGNsc2Z1bmMpCgl7CgkJVGhpcyA9IGNsczsKCQljbGFzc2Z1bmMgPSAoQllQQVNTRlVOQyljbHNmdW5jOwoJfQoKCUNBTExNRU1CRVJGVU5DX0ZVTkMgZ2V0ZnVuYygpCgl7CgkJcmV0dXJuIHJlaW50ZXJwcmV0X2Nhc3Q8Q0FMTE1FTUJFUkZVTkNfRlVOQz4oJmZ1bmNkYXRhWzBdKTsKCX0KCglzdGF0aWMgdm9pZCBDYWxsTWVtYmVyRnVuYygpIENBTExNRU1CRVJGVU5DX0RFQ0xfMTsKCXN0YXRpYyBjb25zdCBpbnQgZnVuY19vZmZzZXQ7CglzdGF0aWMgY29uc3QgaW50IGZ1bmNkYXRhX29mZnNldDsKCn07CiNwcmFnbWEgcGFjayhwb3ApCgojaWZkZWYgX19HTlVDX18KdGVtcGxhdGU8Y2xhc3MgVD4gY29uc3QgaW50IENBTExNRU1CRVJGVU5DPFQ+OjpmdW5jX29mZnNldCA9IG9mZnNldG9mKENBTExNRU1CRVJGVU5DPFQ+LGNsYXNzZnVuYyk7CnRlbXBsYXRlPGNsYXNzIFQ+IGNvbnN0IGludCBDQUxMTUVNQkVSRlVOQzxUPjo6ZnVuY2RhdGFfb2Zmc2V0ID0gb2Zmc2V0b2YoQ0FMTE1FTUJFUkZVTkM8VD4sZnVuY2RhdGEpOwojZWxzZQkvL19NU0NfVkVSCi8vI2RlZmluZSBGSUVMRF9PRkZTRVQodHlwZSwgZmllbGQpICAgICgoaW50KShpbnQqKSYoKCh0eXBlICopMCktPmZpZWxkKSkKCnRlbXBsYXRlPGNsYXNzIFQ+IGNvbnN0IGludCBDQUxMTUVNQkVSRlVOQzxUPjo6ZnVuY19vZmZzZXQgPSBGSUVMRF9PRkZTRVQoQ0FMTE1FTUJFUkZVTkMsY2xhc3NmdW5jKTsKdGVtcGxhdGU8Y2xhc3MgVD4gY29uc3QgaW50IENBTExNRU1CRVJGVU5DPFQ+OjpmdW5jZGF0YV9vZmZzZXQgPSBGSUVMRF9PRkZTRVQoQ0FMTE1FTUJFUkZVTkMsZnVuY2RhdGEpOwojZW5kaWYKCnRlbXBsYXRlPGNsYXNzIFQ+CkNBTExNRU1CRVJGVU5DX0RFQ0xfMiB2b2lkIENBTExNRU1CRVJGVU5DPFQ+OjpDYWxsTWVtYmVyRnVuYygpIAp7CiNpZmRlZiBfX0dOVUNfXwoJX19hc21fXygiY2FsbCAxZlxuXHQiCgkJIjE6IHBvcGwgJSVlYXhcbiIKCQkic3VibCAkNSwlJWVheFxuIgoKCQkic3VibCAlMCwlJWVheFxuIgoJCSJtb3ZsICglJWVheCksICUlZWN4XG4iCgoJCSJhZGQgJTEsICUlZWF4XG4iCgkJIm1vdiAoJSVlYXgpLCAlJWVheFxuIgoKCQkicHVzaCAlJWVjeFxuIgoJCSJjYWxsIColJWVheFxuIgoJCSJhZGRsICQ0LCUlZXNwXG4iCgkJInJldCIKCQk6CgkJOiAiaSIoZnVuY2RhdGFfb2Zmc2V0KSwgImkiKGZ1bmNfb2Zmc2V0KQoJKTsKI2Vsc2UJLy9fTVNDX1ZFUgoJX2FzbXsKCQljYWxsIENhbGxNZW1iZXJGdW5jX2NoZWNrX3BjCgkJQ2FsbE1lbWJlckZ1bmNfY2hlY2tfcGM6CgkJcG9wIGVheAoJCXN1YiBlYXgsNQoKCQlzdWIgZWF4LGZ1bmNkYXRhX29mZnNldAoJCW1vdiBlY3gsW2VheF0KCgkJYWRkIGVheCxmdW5jX29mZnNldAoJCW1vdiBlYXgsIFtlYXhdCgoJCXB1c2ggZWN4CgkJY2FsbCBlYXgKCQlhZGQgZXNwLDQKCQlyZXQKCX0KI2VuZGlmCn0KCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCmV4dGVybiAiQyIgdHlwZWRlZiBpbnQoKkZVTkNfQUREKShpbnQpOwpleHRlcm4gIkMiIGludCBhZGQoRlVOQ19BREQgZnVuYywgaW50IHgsIGludCB5KQp7CglyZXR1cm4gZnVuYyh4KSArIGZ1bmMoeSk7Cn0KCmV4dGVybiAiQyIgdHlwZWRlZiB2b2lkKCpGVU5DX1BSSU5UKShjb25zdCBjaGFyKiwgaW50LCBpbnQpOwpleHRlcm4gIkMiIHZvaWQgcHJpbnQoRlVOQ19QUklOVCBmdW5jLCBpbnQgeCwgaW50IHkpCnsKCWZ1bmMoInByaW50IHg6JWQsIHk6JWRcbiIsIHgsIHkpOwp9CgpjbGFzcyBURVNUCnsKCWludCBhOwoJQ0FMTE1FTUJFUkZVTkM8VEVTVD4gKmNtZl9hZGQsICpjbWZfcHJpbnQ7CnB1YmxpYzoKCglURVNUKGludCB4KSA6IGEoeCkKCXsKCQljbWZfYWRkID0gbmV3IENBTExNRU1CRVJGVU5DPFRFU1Q+KHRoaXMsIGNtZl9mdW5jX2FkZCk7CgkJY21mX3ByaW50ID0gbmV3IENBTExNRU1CRVJGVU5DPFRFU1Q+KHRoaXMsIGNtZl9mdW5jX3ByaW50KTsKCX0KCgl+VEVTVCgpCgl7CgkJZGVsZXRlIGNtZl9hZGQ7CgkJZGVsZXRlIGNtZl9wcmludDsKCX0KCglpbnQgZnVuY19hZGQoaW50IHgpCgl7CgkJcmV0dXJuIGEgKiB4OwoJfQoKCXN0YXRpYyBpbnQgY21mX2Z1bmNfYWRkKFRFU1QqIFRoaXMsIHZvaWQqLCBpbnQgeCkKCXsKCQlyZXR1cm4gVGhpcy0+ZnVuY19hZGQoeCk7Cgl9CgoJdm9pZCBmdW5jX3ByaW50KGNvbnN0IGNoYXIqIGZtdCwgaW50IHgsIGludCB5KQoJewoJCXByaW50ZihmbXQsIHggKiBhLCB5ICogYSk7Cgl9CgoJc3RhdGljIHZvaWQgY21mX2Z1bmNfcHJpbnQoVEVTVCogVGhpcywgdm9pZCosIGNvbnN0IGNoYXIqIGZtdCwgaW50IHgsIGludCB5KQoJewoJCVRoaXMtPmZ1bmNfcHJpbnQoZm10LCB4LCB5KTsKCX0KCglvcGVyYXRvciBGVU5DX0FERCgpCgl7CgkJcmV0dXJuIHJlaW50ZXJwcmV0X2Nhc3Q8RlVOQ19BREQ+KGNtZl9hZGQtPmdldGZ1bmMoKSk7Cgl9CgoJb3BlcmF0b3IgRlVOQ19QUklOVCgpCgl7CgkJcmV0dXJuIHJlaW50ZXJwcmV0X2Nhc3Q8RlVOQ19QUklOVD4oY21mX3ByaW50LT5nZXRmdW5jKCkpOwoJfQp9OwoKCmludCBtYWluKCkKewoJVEVTVCB0KDEwMCk7CgoJcHJpbnRmKCJhZGQgJWRcbiIsIGFkZCh0LCAxLCAyKSk7CgoJcHJpbnQodCwgMywgNCk7CgoJcmV0dXJuIDA7Cn0K