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