Mercurial > pub > dyncall > dyncall
comparison dyncallback/dyncall_callback_x86.c @ 0:3e629dc19168
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:24:28 +0100 |
parents | |
children | d48a8b8d2ef9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3e629dc19168 |
---|---|
1 /* | |
2 | |
3 Package: dyncall | |
4 Library: dyncallback | |
5 File: dyncallback/dyncall_callback_x86.c | |
6 Description: Callback - Implementation for x86 | |
7 License: | |
8 | |
9 Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>, | |
10 Tassilo Philipp <tphilipp@potion-studios.com> | |
11 | |
12 Permission to use, copy, modify, and distribute this software for any | |
13 purpose with or without fee is hereby granted, provided that the above | |
14 copyright notice and this permission notice appear in all copies. | |
15 | |
16 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
17 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
18 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
19 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
21 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
23 | |
24 */ | |
25 | |
26 | |
27 | |
28 #include "dyncall_callback_x86.h" | |
29 #include "dyncall_args_x86.h" | |
30 | |
31 #include "dyncall_alloc_wx.h" | |
32 #include "dyncall_signature.h" | |
33 | |
34 /* | |
35 * assembly thunk entry for callbacks | |
36 */ | |
37 | |
38 extern void dcCallbackThunkEntry(); | |
39 | |
40 /* compute stacksize for callee cleanup calling conventions: | |
41 * | |
42 * stdcall,fastcall_ms,fastcall_gnu | |
43 */ | |
44 | |
45 static int dcbCleanupSize_x86_cdecl(const char* signature) | |
46 { | |
47 return 0; | |
48 } | |
49 | |
50 static int dcbCleanupSize_x86_std(const char* signature) | |
51 { | |
52 const char* ptr = signature; | |
53 int size = 0; | |
54 char ch; | |
55 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) { | |
56 switch(ch) { | |
57 case DC_SIGCHAR_BOOL: | |
58 case DC_SIGCHAR_CHAR: | |
59 case DC_SIGCHAR_SHORT: | |
60 case DC_SIGCHAR_INT: | |
61 case DC_SIGCHAR_LONG: | |
62 case DC_SIGCHAR_POINTER: | |
63 case DC_SIGCHAR_UCHAR: | |
64 case DC_SIGCHAR_USHORT: | |
65 case DC_SIGCHAR_UINT: | |
66 case DC_SIGCHAR_ULONG: | |
67 case DC_SIGCHAR_STRING: | |
68 case DC_SIGCHAR_FLOAT: | |
69 size += 4; | |
70 break; | |
71 case DC_SIGCHAR_DOUBLE: | |
72 case DC_SIGCHAR_LONGLONG: | |
73 case DC_SIGCHAR_ULONGLONG: | |
74 size += 8; | |
75 break; | |
76 } | |
77 } | |
78 return size; | |
79 } | |
80 | |
81 static int dcbCleanupSize_x86_this_ms(const char* signature) | |
82 { | |
83 const char* ptr = signature; | |
84 int size = 0; | |
85 char ch; | |
86 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) | |
87 { | |
88 switch(ch) | |
89 { | |
90 case DC_SIGCHAR_BOOL: | |
91 case DC_SIGCHAR_CHAR: | |
92 case DC_SIGCHAR_SHORT: | |
93 case DC_SIGCHAR_INT: | |
94 case DC_SIGCHAR_LONG: | |
95 case DC_SIGCHAR_POINTER: | |
96 case DC_SIGCHAR_UCHAR: | |
97 case DC_SIGCHAR_USHORT: | |
98 case DC_SIGCHAR_UINT: | |
99 case DC_SIGCHAR_ULONG: | |
100 case DC_SIGCHAR_STRING: | |
101 case DC_SIGCHAR_FLOAT: | |
102 size += 4; | |
103 break; | |
104 case DC_SIGCHAR_DOUBLE: | |
105 case DC_SIGCHAR_LONGLONG: | |
106 case DC_SIGCHAR_ULONGLONG: | |
107 size += 8; | |
108 break; | |
109 } | |
110 } | |
111 return size; | |
112 } | |
113 | |
114 static int dcbCleanupSize_x86_fast_ms(const char* signature) | |
115 { | |
116 const char* ptr = signature; | |
117 int size = 0; | |
118 int regs = 0; | |
119 char ch; | |
120 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) | |
121 { | |
122 switch(ch) | |
123 { | |
124 case DC_SIGCHAR_BOOL: | |
125 case DC_SIGCHAR_CHAR: | |
126 case DC_SIGCHAR_SHORT: | |
127 case DC_SIGCHAR_INT: | |
128 case DC_SIGCHAR_LONG: | |
129 case DC_SIGCHAR_POINTER: | |
130 case DC_SIGCHAR_UCHAR: | |
131 case DC_SIGCHAR_USHORT: | |
132 case DC_SIGCHAR_UINT: | |
133 case DC_SIGCHAR_ULONG: | |
134 case DC_SIGCHAR_STRING: | |
135 if (regs < 2) regs++; | |
136 else size += 4; | |
137 break; | |
138 case DC_SIGCHAR_FLOAT: | |
139 size += 4; | |
140 break; | |
141 case DC_SIGCHAR_DOUBLE: | |
142 size += 8; | |
143 break; | |
144 case DC_SIGCHAR_LONGLONG: | |
145 case DC_SIGCHAR_ULONGLONG: | |
146 size += 8; | |
147 break; | |
148 } | |
149 } | |
150 return size; | |
151 } | |
152 | |
153 static int dcbCleanupSize_x86_fast_gnu(const char* signature) | |
154 { | |
155 const char* ptr = signature; | |
156 char ch; | |
157 int size = 0; | |
158 int regs = 0; | |
159 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) { | |
160 switch(ch) { | |
161 case DC_SIGCHAR_FLOAT: | |
162 size += 4; | |
163 break; | |
164 case DC_SIGCHAR_DOUBLE: | |
165 size += 8; | |
166 break; | |
167 case DC_SIGCHAR_LONGLONG: | |
168 case DC_SIGCHAR_ULONGLONG: | |
169 regs = 2; | |
170 size += 8; | |
171 break; | |
172 default: | |
173 if (regs < 2) regs++; | |
174 else size += 4; | |
175 break; | |
176 } | |
177 } | |
178 return size; | |
179 } | |
180 | |
181 void dcbInitCallback(DCCallback* pcb, const char* signature, DCCallbackHandler* handler, void* userdata) | |
182 { | |
183 const char* ptr; | |
184 char ch; | |
185 int mode; | |
186 pcb->handler = handler; | |
187 pcb->userdata = userdata; | |
188 | |
189 ptr = signature; | |
190 ch = *ptr; | |
191 | |
192 /* x86 hints: */ | |
193 | |
194 mode = DC_CALL_C_X86_CDECL; | |
195 | |
196 if(ch == DC_SIGCHAR_CC_PREFIX) | |
197 { | |
198 ptr++; | |
199 ch = *ptr++; | |
200 switch(ch) { | |
201 case DC_SIGCHAR_CC_STDCALL: mode = DC_CALL_C_X86_WIN32_STD; break; | |
202 case DC_SIGCHAR_CC_THISCALL_MS: mode = DC_CALL_C_X86_WIN32_THIS_MS; break; | |
203 case DC_SIGCHAR_CC_FASTCALL_GNU: mode = DC_CALL_C_X86_WIN32_FAST_GNU; break; | |
204 case DC_SIGCHAR_CC_FASTCALL_MS: mode = DC_CALL_C_X86_WIN32_FAST_MS; break; | |
205 } | |
206 } | |
207 | |
208 /* x86 configuration: */ | |
209 | |
210 switch(mode) { | |
211 case DC_CALL_C_X86_CDECL: | |
212 pcb->args_vt = &dcArgsVT_default; | |
213 pcb->stack_cleanup = dcbCleanupSize_x86_cdecl(ptr); | |
214 break; | |
215 case DC_CALL_C_X86_WIN32_STD: | |
216 pcb->args_vt = &dcArgsVT_default; | |
217 pcb->stack_cleanup = dcbCleanupSize_x86_std(ptr); | |
218 break; | |
219 case DC_CALL_C_X86_WIN32_THIS_MS: | |
220 pcb->args_vt = &dcArgsVT_this_ms; | |
221 pcb->stack_cleanup = dcbCleanupSize_x86_this_ms(ptr); | |
222 break; | |
223 case DC_CALL_C_X86_WIN32_FAST_MS: | |
224 pcb->args_vt = &dcArgsVT_fast_ms; | |
225 pcb->stack_cleanup = dcbCleanupSize_x86_fast_ms(ptr); | |
226 break; | |
227 case DC_CALL_C_X86_WIN32_FAST_GNU: | |
228 pcb->args_vt = &dcArgsVT_fast_gnu; | |
229 pcb->stack_cleanup = dcbCleanupSize_x86_fast_gnu(ptr); | |
230 break; | |
231 } | |
232 | |
233 #if defined(DC_PLAN9) | |
234 /* HACK for Plan9 - 'reuse' pcb->stack_cleanup as a flag | |
235 to indicate if return value is 64bit. The field is not | |
236 used anyways as the caller is responsible to clean up | |
237 the stack in Plan9. If set to '1' the callback kernel | |
238 takes into account an extra stack-parameter (pointer | |
239 to 64bit return value). | |
240 I thought of introducing a new field, but for one single | |
241 x86 calling convention out of many, it seemed overkill | |
242 to change the struct for everybody else. Maybe renaming | |
243 would be a good idea, though. ~ Tassilo | |
244 */ | |
245 while(*ptr) { | |
246 if(*ptr++ == DC_SIGCHAR_ENDARG) { | |
247 pcb->stack_cleanup = (*ptr == DC_SIGCHAR_LONGLONG) || (*ptr == DC_SIGCHAR_ULONGLONG); | |
248 break; | |
249 } | |
250 } | |
251 #endif | |
252 } | |
253 | |
254 /* | |
255 * callback constructor | |
256 */ | |
257 | |
258 DCCallback* dcbNewCallback(const char* signature, DCCallbackHandler* handler, void* userdata) | |
259 { | |
260 int err; | |
261 DCCallback* pcb; | |
262 err = dcAllocWX(sizeof(DCCallback), (void**) &pcb); | |
263 if (err != 0) return 0; | |
264 | |
265 dcbInitThunk(&pcb->thunk, dcCallbackThunkEntry); | |
266 dcbInitCallback(pcb, signature, handler, userdata); | |
267 return pcb; | |
268 } | |
269 | |
270 /* | |
271 * free | |
272 */ | |
273 | |
274 void dcbFreeCallback(DCCallback* pcb) | |
275 { | |
276 dcFreeWX(pcb, sizeof(DCCallback)); | |
277 } | |
278 | |
279 void* dcbGetUserData(DCCallback* pcb) | |
280 { | |
281 return pcb->userdata; | |
282 } |