99_fastcall.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include <stdio.h>
  2. #include <assert.h>
  3. #ifndef _WIN32
  4. #define __fastcall __attribute((fastcall))
  5. #endif
  6. #if 1
  7. #define SYMBOL(x) _##x
  8. #else
  9. #define SYMBOL(x) x
  10. #endif
  11. /////////////////////////////////////////////////////////////////////////
  12. ////////// TRAP FRAMEWORK
  13. /////////////////////////////////////////////////////////////////////////
  14. // if you cast 'TRAP' to a function pointer and call it,
  15. // it will save all 8 registers,
  16. // and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'),
  17. // in C-code you can pop DWORDs from stack and modify registers
  18. //
  19. void *SYMBOL(trap_handler);
  20. extern unsigned char SYMBOL(trap)[];
  21. asm (
  22. ".text;"
  23. "_trap:;"
  24. "pushl %esp;"
  25. "pusha;"
  26. "addl $0x4, 0xc(%esp);"
  27. "pushl %esp;"
  28. "call *_trap_handler;"
  29. "addl $0x4, %esp;"
  30. "movl 0xc(%esp), %eax;"
  31. "movl %eax, 0x20(%esp);"
  32. "popa;"
  33. "popl %esp;"
  34. "ret;"
  35. );
  36. struct trapframe {
  37. unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
  38. };
  39. #define M_FLOAT(addr) (*(float *)(addr))
  40. #define M_DWORD(addr) (*(unsigned *)(addr))
  41. #define M_WORD(addr) (*(unsigned short *)(addr))
  42. #define M_BYTE(addr) (*(unsigned char *)(addr))
  43. #define R_EAX ((tf)->eax)
  44. #define R_ECX ((tf)->ecx)
  45. #define R_EDX ((tf)->edx)
  46. #define R_EBX ((tf)->ebx)
  47. #define R_ESP ((tf)->esp)
  48. #define R_EBP ((tf)->ebp)
  49. #define R_ESI ((tf)->esi)
  50. #define R_EDI ((tf)->edi)
  51. #define ARG(x) (M_DWORD(R_ESP + (x) * 4))
  52. #define RETN(x) do { \
  53. M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \
  54. R_ESP += (x); \
  55. } while (0)
  56. #define DUMP() do { \
  57. unsigned i; \
  58. printf("EAX: %08X\n", R_EAX); \
  59. printf("ECX: %08X\n", R_ECX); \
  60. printf("EDX: %08X\n", R_EDX); \
  61. printf("EBX: %08X\n", R_EBX); \
  62. printf("ESP: %08X\n", R_ESP); \
  63. printf("EBP: %08X\n", R_EBP); \
  64. printf("ESI: %08X\n", R_ESI); \
  65. printf("EDI: %08X\n", R_EDI); \
  66. printf("\n"); \
  67. printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \
  68. for (i = 1; i <= 8; i++) { \
  69. printf("[ARG%4d]: %08X\n", i, ARG(i)); \
  70. } \
  71. } while (0)
  72. #define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x))
  73. #define TRAP ((void *) &SYMBOL(trap))
  74. /////////////////////////////////////////////////////////////////////////
  75. ////////// SAFECALL FRAMEWORK
  76. /////////////////////////////////////////////////////////////////////////
  77. // this framework will convert any calling convention to cdecl
  78. // usage: first set call target with 'SET_SAFECALL_TARGET(x)'
  79. // then cast 'SAFECALL' to target function pointer type and invoke it
  80. // after calling, 'ESPDIFF' is the difference of old and new esp
  81. void *SYMBOL(sc_call_target);
  82. unsigned SYMBOL(sc_retn_addr);
  83. unsigned SYMBOL(sc_old_esp);
  84. unsigned SYMBOL(sc_new_esp);
  85. extern unsigned char SYMBOL(safecall)[];
  86. asm (
  87. ".text;"
  88. "_safecall:;"
  89. "popl _sc_retn_addr;"
  90. "movl %esp, _sc_old_esp;"
  91. "call *_sc_call_target;"
  92. "movl %esp, _sc_new_esp;"
  93. "movl _sc_old_esp, %esp;"
  94. "jmp *_sc_retn_addr;"
  95. );
  96. #define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x))
  97. #define SAFECALL ((void *) &SYMBOL(safecall))
  98. #define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp))
  99. /////////////////////////////////////////////////////////////////////////
  100. ////////// TEST FASTCALL INVOKE
  101. /////////////////////////////////////////////////////////////////////////
  102. void check_fastcall_invoke_0(struct trapframe *tf)
  103. {
  104. //DUMP();
  105. RETN(0);
  106. }
  107. void check_fastcall_invoke_1(struct trapframe *tf)
  108. {
  109. //DUMP();
  110. assert(R_ECX == 0x11111111);
  111. RETN(0);
  112. }
  113. void check_fastcall_invoke_2(struct trapframe *tf)
  114. {
  115. //DUMP();
  116. assert(R_ECX == 0x11111111);
  117. assert(R_EDX == 0x22222222);
  118. RETN(0);
  119. }
  120. void check_fastcall_invoke_3(struct trapframe *tf)
  121. {
  122. //DUMP();
  123. assert(R_ECX == 0x11111111);
  124. assert(R_EDX == 0x22222222);
  125. assert(ARG(1) == 0x33333333);
  126. RETN(1*4);
  127. }
  128. void check_fastcall_invoke_4(struct trapframe *tf)
  129. {
  130. //DUMP();
  131. assert(R_ECX == 0x11111111);
  132. assert(R_EDX == 0x22222222);
  133. assert(ARG(1) == 0x33333333);
  134. assert(ARG(2) == 0x44444444);
  135. RETN(2*4);
  136. }
  137. void check_fastcall_invoke_5(struct trapframe *tf)
  138. {
  139. //DUMP();
  140. assert(R_ECX == 0x11111111);
  141. assert(R_EDX == 0x22222222);
  142. assert(ARG(1) == 0x33333333);
  143. assert(ARG(2) == 0x44444444);
  144. assert(ARG(3) == 0x55555555);
  145. RETN(3*4);
  146. }
  147. void test_fastcall_invoke()
  148. {
  149. SET_TRAP_HANDLER(check_fastcall_invoke_0);
  150. ((void __fastcall (*)(void)) TRAP)();
  151. SET_TRAP_HANDLER(check_fastcall_invoke_1);
  152. ((void __fastcall (*)(unsigned)) TRAP)(0x11111111);
  153. SET_TRAP_HANDLER(check_fastcall_invoke_2);
  154. ((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222);
  155. SET_TRAP_HANDLER(check_fastcall_invoke_3);
  156. ((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333);
  157. SET_TRAP_HANDLER(check_fastcall_invoke_4);
  158. ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444);
  159. SET_TRAP_HANDLER(check_fastcall_invoke_5);
  160. ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555);
  161. }
  162. /////////////////////////////////////////////////////////////////////////
  163. ////////// TEST FUNCTION CODE GENERATION
  164. /////////////////////////////////////////////////////////////////////////
  165. int __fastcall check_fastcall_espdiff_0(void)
  166. {
  167. return 0;
  168. }
  169. int __fastcall check_fastcall_espdiff_1(int a)
  170. {
  171. return a;
  172. }
  173. int __fastcall check_fastcall_espdiff_2(int a, int b)
  174. {
  175. return a + b;
  176. }
  177. int __fastcall check_fastcall_espdiff_3(int a, int b, int c)
  178. {
  179. return a + b + c;
  180. }
  181. int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d)
  182. {
  183. return a + b + c + d;
  184. }
  185. int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e)
  186. {
  187. return a + b + c + d + e;
  188. }
  189. void test_fastcall_espdiff()
  190. {
  191. int x;
  192. SET_SAFECALL_TARGET(check_fastcall_espdiff_0);
  193. x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)();
  194. assert(x == 0);
  195. assert(ESPDIFF == 0);
  196. SET_SAFECALL_TARGET(check_fastcall_espdiff_1);
  197. x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1);
  198. assert(x == 1);
  199. assert(ESPDIFF == 0);
  200. SET_SAFECALL_TARGET(check_fastcall_espdiff_2);
  201. x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2);
  202. assert(x == 1 + 2);
  203. assert(ESPDIFF == 0);
  204. SET_SAFECALL_TARGET(check_fastcall_espdiff_3);
  205. x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3);
  206. assert(x == 1 + 2 + 3);
  207. assert(ESPDIFF == 1*4);
  208. SET_SAFECALL_TARGET(check_fastcall_espdiff_4);
  209. x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4);
  210. assert(x == 1 + 2 + 3 + 4);
  211. assert(ESPDIFF == 2*4);
  212. SET_SAFECALL_TARGET(check_fastcall_espdiff_5);
  213. x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5);
  214. assert(x == 1 + 2 + 3 + 4 + 5);
  215. assert(ESPDIFF == 3*4);
  216. }
  217. int main()
  218. {
  219. #define N 10000
  220. int i;
  221. for (i = 1; i <= N; i++) {
  222. test_fastcall_espdiff();
  223. }
  224. for (i = 1; i <= N; i++) {
  225. test_fastcall_invoke();
  226. }
  227. puts("TEST OK");
  228. return 0;
  229. }