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 }