Mercurial > pub > dyncall > dyncall
annotate dyncallback/dyncall_callback_x86.c @ 364:3bdd326dc269
- Todo entries
- some clarifications in code about GNU thiscalls (which are effectively idential to cdecl calls)
* took away own mode identifier, as aliasing to cdecl now
- cleanups
author | Tassilo Philipp |
---|---|
date | Tue, 14 Apr 2020 19:35:30 +0200 |
parents | 30aae7371373 |
children | ddfb9577a00e |
rev | line source |
---|---|
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 | |
364 | 9 Copyright (c) 2007-2020 Daniel Adler <dadler@uni-goettingen.de>, |
0 | 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 | |
152
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
27 #include "dyncall_callback.h" |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
28 #include "dyncall_alloc_wx.h" |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
29 #include "dyncall_thunk.h" |
0 | 30 #include "dyncall_args_x86.h" |
31 | |
152
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
32 /* Callback symbol. */ |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
33 extern void dcCallbackThunkEntry(); |
0 | 34 |
152
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
35 struct DCCallback |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
36 { |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
37 DCThunk thunk; /* offset 0, size 16 */ |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
38 DCCallbackHandler* handler; /* offset 16 */ |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
39 DCArgsVT* args_vt; /* offset 20 */ |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
40 size_t stack_cleanup; /* offset 24 */ |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
41 void* userdata; /* offset 28 */ |
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
42 }; |
0 | 43 |
44 | |
45 /* compute stacksize for callee cleanup calling conventions: | |
46 * | |
152
d48a8b8d2ef9
- integrated all headers containing DCCallback definition into the translation units used (arm64 already avoided this pointless header, so following that style)
cslag
parents:
0
diff
changeset
|
47 * cdecl,stdcall,thiscall_ms,fastcall_ms,fastcall_gnu |
0 | 48 */ |
49 | |
50 static int dcbCleanupSize_x86_cdecl(const char* signature) | |
51 { | |
52 return 0; | |
53 } | |
54 | |
55 static int dcbCleanupSize_x86_std(const char* signature) | |
56 { | |
57 const char* ptr = signature; | |
58 int size = 0; | |
59 char ch; | |
60 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) { | |
61 switch(ch) { | |
62 case DC_SIGCHAR_BOOL: | |
63 case DC_SIGCHAR_CHAR: | |
64 case DC_SIGCHAR_SHORT: | |
65 case DC_SIGCHAR_INT: | |
66 case DC_SIGCHAR_LONG: | |
67 case DC_SIGCHAR_POINTER: | |
68 case DC_SIGCHAR_UCHAR: | |
69 case DC_SIGCHAR_USHORT: | |
70 case DC_SIGCHAR_UINT: | |
71 case DC_SIGCHAR_ULONG: | |
72 case DC_SIGCHAR_STRING: | |
73 case DC_SIGCHAR_FLOAT: | |
74 size += 4; | |
75 break; | |
76 case DC_SIGCHAR_DOUBLE: | |
77 case DC_SIGCHAR_LONGLONG: | |
78 case DC_SIGCHAR_ULONGLONG: | |
79 size += 8; | |
80 break; | |
81 } | |
82 } | |
83 return size; | |
84 } | |
85 | |
86 static int dcbCleanupSize_x86_this_ms(const char* signature) | |
87 { | |
88 const char* ptr = signature; | |
89 int size = 0; | |
90 char ch; | |
91 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) | |
92 { | |
93 switch(ch) | |
94 { | |
95 case DC_SIGCHAR_BOOL: | |
96 case DC_SIGCHAR_CHAR: | |
97 case DC_SIGCHAR_SHORT: | |
98 case DC_SIGCHAR_INT: | |
99 case DC_SIGCHAR_LONG: | |
100 case DC_SIGCHAR_POINTER: | |
101 case DC_SIGCHAR_UCHAR: | |
102 case DC_SIGCHAR_USHORT: | |
103 case DC_SIGCHAR_UINT: | |
104 case DC_SIGCHAR_ULONG: | |
105 case DC_SIGCHAR_STRING: | |
106 case DC_SIGCHAR_FLOAT: | |
107 size += 4; | |
108 break; | |
109 case DC_SIGCHAR_DOUBLE: | |
110 case DC_SIGCHAR_LONGLONG: | |
111 case DC_SIGCHAR_ULONGLONG: | |
112 size += 8; | |
113 break; | |
114 } | |
115 } | |
116 return size; | |
117 } | |
118 | |
119 static int dcbCleanupSize_x86_fast_ms(const char* signature) | |
120 { | |
121 const char* ptr = signature; | |
122 int size = 0; | |
123 int regs = 0; | |
124 char ch; | |
125 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) | |
126 { | |
127 switch(ch) | |
128 { | |
129 case DC_SIGCHAR_BOOL: | |
130 case DC_SIGCHAR_CHAR: | |
131 case DC_SIGCHAR_SHORT: | |
132 case DC_SIGCHAR_INT: | |
133 case DC_SIGCHAR_LONG: | |
134 case DC_SIGCHAR_POINTER: | |
135 case DC_SIGCHAR_UCHAR: | |
136 case DC_SIGCHAR_USHORT: | |
137 case DC_SIGCHAR_UINT: | |
138 case DC_SIGCHAR_ULONG: | |
139 case DC_SIGCHAR_STRING: | |
140 if (regs < 2) regs++; | |
141 else size += 4; | |
142 break; | |
143 case DC_SIGCHAR_FLOAT: | |
144 size += 4; | |
145 break; | |
146 case DC_SIGCHAR_DOUBLE: | |
147 size += 8; | |
148 break; | |
149 case DC_SIGCHAR_LONGLONG: | |
150 case DC_SIGCHAR_ULONGLONG: | |
151 size += 8; | |
152 break; | |
153 } | |
154 } | |
155 return size; | |
156 } | |
157 | |
158 static int dcbCleanupSize_x86_fast_gnu(const char* signature) | |
159 { | |
160 const char* ptr = signature; | |
161 char ch; | |
162 int size = 0; | |
163 int regs = 0; | |
164 while( (ch = *ptr++) != DC_SIGCHAR_ENDARG ) { | |
165 switch(ch) { | |
166 case DC_SIGCHAR_FLOAT: | |
167 size += 4; | |
168 break; | |
169 case DC_SIGCHAR_DOUBLE: | |
170 size += 8; | |
171 break; | |
172 case DC_SIGCHAR_LONGLONG: | |
173 case DC_SIGCHAR_ULONGLONG: | |
174 regs = 2; | |
175 size += 8; | |
176 break; | |
177 default: | |
178 if (regs < 2) regs++; | |
179 else size += 4; | |
180 break; | |
181 } | |
182 } | |
183 return size; | |
184 } | |
185 | |
186 void dcbInitCallback(DCCallback* pcb, const char* signature, DCCallbackHandler* handler, void* userdata) | |
187 { | |
188 const char* ptr; | |
189 char ch; | |
190 int mode; | |
191 pcb->handler = handler; | |
192 pcb->userdata = userdata; | |
193 | |
194 ptr = signature; | |
195 ch = *ptr; | |
196 | |
197 /* x86 hints: */ | |
198 | |
199 mode = DC_CALL_C_X86_CDECL; | |
200 | |
201 if(ch == DC_SIGCHAR_CC_PREFIX) | |
202 { | |
203 ptr++; | |
204 ch = *ptr++; | |
205 switch(ch) { | |
358
30aae7371373
- extended signature with calling convention mode switches for fastcall (gnu), default, cdecl, stdcall, arm (arm), arm (thumb), syscall
Tassilo Philipp
parents:
281
diff
changeset
|
206 case DC_SIGCHAR_CC_DEFAULT: mode = DC_CALL_C_DEFAULT; break; |
364 | 207 case DC_SIGCHAR_CC_THISCALL_GNU: // == cdecl |
358
30aae7371373
- extended signature with calling convention mode switches for fastcall (gnu), default, cdecl, stdcall, arm (arm), arm (thumb), syscall
Tassilo Philipp
parents:
281
diff
changeset
|
208 case DC_SIGCHAR_CC_CDECL: mode = DC_CALL_C_X86_CDECL; break; |
0 | 209 case DC_SIGCHAR_CC_STDCALL: mode = DC_CALL_C_X86_WIN32_STD; break; |
358
30aae7371373
- extended signature with calling convention mode switches for fastcall (gnu), default, cdecl, stdcall, arm (arm), arm (thumb), syscall
Tassilo Philipp
parents:
281
diff
changeset
|
210 case DC_SIGCHAR_CC_FASTCALL_MS: mode = DC_CALL_C_X86_WIN32_FAST_MS; break; |
30aae7371373
- extended signature with calling convention mode switches for fastcall (gnu), default, cdecl, stdcall, arm (arm), arm (thumb), syscall
Tassilo Philipp
parents:
281
diff
changeset
|
211 case DC_SIGCHAR_CC_FASTCALL_GNU: mode = DC_CALL_C_X86_WIN32_FAST_GNU; break; |
0 | 212 case DC_SIGCHAR_CC_THISCALL_MS: mode = DC_CALL_C_X86_WIN32_THIS_MS; break; |
213 } | |
214 } | |
215 | |
216 /* x86 configuration: */ | |
217 | |
218 switch(mode) { | |
219 case DC_CALL_C_X86_CDECL: | |
220 pcb->args_vt = &dcArgsVT_default; | |
221 pcb->stack_cleanup = dcbCleanupSize_x86_cdecl(ptr); | |
222 break; | |
223 case DC_CALL_C_X86_WIN32_STD: | |
224 pcb->args_vt = &dcArgsVT_default; | |
225 pcb->stack_cleanup = dcbCleanupSize_x86_std(ptr); | |
226 break; | |
227 case DC_CALL_C_X86_WIN32_FAST_MS: | |
228 pcb->args_vt = &dcArgsVT_fast_ms; | |
229 pcb->stack_cleanup = dcbCleanupSize_x86_fast_ms(ptr); | |
230 break; | |
231 case DC_CALL_C_X86_WIN32_FAST_GNU: | |
232 pcb->args_vt = &dcArgsVT_fast_gnu; | |
233 pcb->stack_cleanup = dcbCleanupSize_x86_fast_gnu(ptr); | |
234 break; | |
364 | 235 case DC_CALL_C_X86_WIN32_THIS_MS: |
236 pcb->args_vt = &dcArgsVT_this_ms; | |
237 pcb->stack_cleanup = dcbCleanupSize_x86_this_ms(ptr); | |
238 break; | |
0 | 239 } |
240 | |
241 #if defined(DC_PLAN9) | |
242 /* HACK for Plan9 - 'reuse' pcb->stack_cleanup as a flag | |
243 to indicate if return value is 64bit. The field is not | |
244 used anyways as the caller is responsible to clean up | |
245 the stack in Plan9. If set to '1' the callback kernel | |
246 takes into account an extra stack-parameter (pointer | |
247 to 64bit return value). | |
248 I thought of introducing a new field, but for one single | |
249 x86 calling convention out of many, it seemed overkill | |
250 to change the struct for everybody else. Maybe renaming | |
251 would be a good idea, though. ~ Tassilo | |
252 */ | |
253 while(*ptr) { | |
254 if(*ptr++ == DC_SIGCHAR_ENDARG) { | |
255 pcb->stack_cleanup = (*ptr == DC_SIGCHAR_LONGLONG) || (*ptr == DC_SIGCHAR_ULONGLONG); | |
256 break; | |
257 } | |
258 } | |
259 #endif | |
260 } | |
261 | |
262 /* | |
263 * callback constructor | |
264 */ | |
265 | |
266 DCCallback* dcbNewCallback(const char* signature, DCCallbackHandler* handler, void* userdata) | |
267 { | |
268 int err; | |
269 DCCallback* pcb; | |
270 err = dcAllocWX(sizeof(DCCallback), (void**) &pcb); | |
202 | 271 if(err) |
272 return NULL; | |
0 | 273 |
274 dcbInitThunk(&pcb->thunk, dcCallbackThunkEntry); | |
275 dcbInitCallback(pcb, signature, handler, userdata); | |
202 | 276 |
277 err = dcInitExecWX(pcb, sizeof(DCCallback)); | |
278 if(err) { | |
279 dcFreeWX(pcb, sizeof(DCCallback)); | |
280 return NULL; | |
281 } | |
282 | |
0 | 283 return pcb; |
284 } | |
285 | |
286 /* | |
287 * free | |
288 */ | |
289 | |
290 void dcbFreeCallback(DCCallback* pcb) | |
291 { | |
292 dcFreeWX(pcb, sizeof(DCCallback)); | |
293 } | |
294 | |
295 void* dcbGetUserData(DCCallback* pcb) | |
296 { | |
297 return pcb->userdata; | |
298 } |