fork(2) download
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stddef.h>
  4.  
  5. #include <Windows.h>
  6.  
  7. /*
  8. mingw (tested with gcc4.7.2, gcc4.8.1)
  9. g++ cpp105-628.cpp -o cpp105-628-gcc
  10.  
  11. vc (tested with vc2008,vc2010,vc2013)
  12. cl /c cpp105-628.cpp
  13. link /INCREMENTAL:NO cpp105-628.obj
  14. */
  15.  
  16. /*****************************************************************************************/
  17.  
  18. #ifdef __GNUC__
  19. #define CALLMEMBERFUNC_DECL_1 __attribute__ ((__optimize__(0,"omit-frame-pointer")))
  20. #define CALLMEMBERFUNC_DECL_2
  21. #else //_MSC_VER
  22. #define CALLMEMBERFUNC_DECL_1
  23. #define CALLMEMBERFUNC_DECL_2 __declspec(naked)
  24. #endif
  25.  
  26. #pragma pack(push,1)
  27. template<class T>
  28. struct CALLMEMBERFUNC
  29. {
  30. typedef void(*CALLMEMBERFUNC_FUNC)();
  31. typedef void(*BYPASSFUNC)(T* This, void* /*return address*/, ...);
  32.  
  33. T* This;
  34. BYPASSFUNC classfunc;
  35. char funcdata[40];
  36.  
  37. template<class F>
  38. CALLMEMBERFUNC(T* cls, F clsfunc)
  39. {
  40. memcpy((void*)funcdata, (void*)CallMemberFunc, sizeof(funcdata));
  41. set(cls, clsfunc);
  42. }
  43.  
  44. void *operator new(size_t size)
  45. {
  46. return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  47. }
  48.  
  49. void operator delete(void* p)
  50. {
  51. VirtualFree(p, 0, MEM_RELEASE);
  52. }
  53.  
  54. template<class F>
  55. void set(T* cls, F clsfunc)
  56. {
  57. This = cls;
  58. classfunc = (BYPASSFUNC)clsfunc;
  59. }
  60.  
  61. CALLMEMBERFUNC_FUNC getfunc()
  62. {
  63. return reinterpret_cast<CALLMEMBERFUNC_FUNC>(&funcdata[0]);
  64. }
  65.  
  66. static void CallMemberFunc() CALLMEMBERFUNC_DECL_1;
  67. static const int func_offset;
  68. static const int funcdata_offset;
  69.  
  70. };
  71. #pragma pack(pop)
  72.  
  73. #ifdef __GNUC__
  74. template<class T> const int CALLMEMBERFUNC<T>::func_offset = offsetof(CALLMEMBERFUNC<T>,classfunc);
  75. template<class T> const int CALLMEMBERFUNC<T>::funcdata_offset = offsetof(CALLMEMBERFUNC<T>,funcdata);
  76. #else //_MSC_VER
  77. //#define FIELD_OFFSET(type, field) ((int)(int*)&(((type *)0)->field))
  78.  
  79. template<class T> const int CALLMEMBERFUNC<T>::func_offset = FIELD_OFFSET(CALLMEMBERFUNC,classfunc);
  80. template<class T> const int CALLMEMBERFUNC<T>::funcdata_offset = FIELD_OFFSET(CALLMEMBERFUNC,funcdata);
  81. #endif
  82.  
  83. template<class T>
  84. CALLMEMBERFUNC_DECL_2 void CALLMEMBERFUNC<T>::CallMemberFunc()
  85. {
  86. #ifdef __GNUC__
  87. __asm__("call 1f\n\t"
  88. "1: popl %%eax\n"
  89. "subl $5,%%eax\n"
  90.  
  91. "subl %0,%%eax\n"
  92. "movl (%%eax), %%ecx\n"
  93.  
  94. "add %1, %%eax\n"
  95. "mov (%%eax), %%eax\n"
  96.  
  97. "push %%ecx\n"
  98. "call *%%eax\n"
  99. "addl $4,%%esp\n"
  100. "ret"
  101. :
  102. : "i"(funcdata_offset), "i"(func_offset)
  103. );
  104. #else //_MSC_VER
  105. _asm{
  106. call CallMemberFunc_check_pc
  107. CallMemberFunc_check_pc:
  108. pop eax
  109. sub eax,5
  110.  
  111. sub eax,funcdata_offset
  112. mov ecx,[eax]
  113.  
  114. add eax,func_offset
  115. mov eax, [eax]
  116.  
  117. push ecx
  118. call eax
  119. add esp,4
  120. ret
  121. }
  122. #endif
  123. }
  124.  
  125. /*****************************************************************************************/
  126.  
  127. extern "C" typedef int(*FUNC_ADD)(int);
  128. extern "C" int add(FUNC_ADD func, int x, int y)
  129. {
  130. return func(x) + func(y);
  131. }
  132.  
  133. extern "C" typedef void(*FUNC_PRINT)(const char*, int, int);
  134. extern "C" void print(FUNC_PRINT func, int x, int y)
  135. {
  136. func("print x:%d, y:%d\n", x, y);
  137. }
  138.  
  139. class TEST
  140. {
  141. int a;
  142. CALLMEMBERFUNC<TEST> *cmf_add, *cmf_print;
  143. public:
  144.  
  145. TEST(int x) : a(x)
  146. {
  147. cmf_add = new CALLMEMBERFUNC<TEST>(this, cmf_func_add);
  148. cmf_print = new CALLMEMBERFUNC<TEST>(this, cmf_func_print);
  149. }
  150.  
  151. ~TEST()
  152. {
  153. delete cmf_add;
  154. delete cmf_print;
  155. }
  156.  
  157. int func_add(int x)
  158. {
  159. return a * x;
  160. }
  161.  
  162. static int cmf_func_add(TEST* This, void*, int x)
  163. {
  164. return This->func_add(x);
  165. }
  166.  
  167. void func_print(const char* fmt, int x, int y)
  168. {
  169. printf(fmt, x * a, y * a);
  170. }
  171.  
  172. static void cmf_func_print(TEST* This, void*, const char* fmt, int x, int y)
  173. {
  174. This->func_print(fmt, x, y);
  175. }
  176.  
  177. operator FUNC_ADD()
  178. {
  179. return reinterpret_cast<FUNC_ADD>(cmf_add->getfunc());
  180. }
  181.  
  182. operator FUNC_PRINT()
  183. {
  184. return reinterpret_cast<FUNC_PRINT>(cmf_print->getfunc());
  185. }
  186. };
  187.  
  188.  
  189. int main()
  190. {
  191. TEST t(100);
  192.  
  193. printf("add %d\n", add(t, 1, 2));
  194.  
  195. print(t, 3, 4);
  196.  
  197. return 0;
  198. }
  199.  
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:5:21: fatal error: Windows.h: No such file or directory
 #include <Windows.h>
                     ^
compilation terminated.
stdout
Standard output is empty