source: EcnlProtoTool/trunk/tcc-0.9.27/tests/tests2/99_fastcall.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 7.0 KB
Line 
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
23void *SYMBOL(trap_handler);
24
25extern unsigned char SYMBOL(trap)[];
26asm (
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
42struct 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
97void *SYMBOL(sc_call_target);
98unsigned SYMBOL(sc_retn_addr);
99unsigned SYMBOL(sc_old_esp);
100unsigned SYMBOL(sc_new_esp);
101
102extern unsigned char SYMBOL(safecall)[];
103asm (
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
123void check_fastcall_invoke_0(struct trapframe *tf)
124{
125 //DUMP();
126 RETN(0);
127}
128
129void check_fastcall_invoke_1(struct trapframe *tf)
130{
131 //DUMP();
132 assert(R_ECX == 0x11111111);
133 RETN(0);
134}
135void check_fastcall_invoke_2(struct trapframe *tf)
136{
137 //DUMP();
138 assert(R_ECX == 0x11111111);
139 assert(R_EDX == 0x22222222);
140 RETN(0);
141}
142void 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}
150void 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
160void 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
171void 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
197int __fastcall check_fastcall_espdiff_0(void)
198{
199 return 0;
200}
201
202int __fastcall check_fastcall_espdiff_1(int a)
203{
204 return a;
205}
206
207int __fastcall check_fastcall_espdiff_2(int a, int b)
208{
209 return a + b;
210}
211
212int __fastcall check_fastcall_espdiff_3(int a, int b, int c)
213{
214 return a + b + c;
215}
216
217int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d)
218{
219 return a + b + c + d;
220}
221
222int __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
227void 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
261int 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}
Note: See TracBrowser for help on using the repository browser.