0
|
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 }
|