Mercurial > pub > dyncall > dyncall
comparison dyncall/dyncall_callvm_x64.c @ 533:71c884e610f0
- integration of patches from Raphael Luba, Thekla, Inc.:
* integration of aggregate-by-value (struct, union) support patch for x64 (win and sysv)
* windows/x64 asm additions to specify how stack unwinds (help for debuggers, exception handling, etc.)
* see Changelog for details
- new calling convention modes for thiscalls (platform agnostic, was specific before)
* new signature character for platform agnostic thiscalls ('*' / DC_SIGCHAR_CC_THISCALL)
- dcCallF(), dcVCallF(), dcArgF() and dcVArgF():
* added support for aggregates-by-value (wasn't part of patch)
* change that those functions don't implicitly call dcReset() anymore, which was unflexible (breaking change)
- added macros to feature test implementation for aggregate-by-value and syscall support
- changed libdyncall_s.lib and libdyncallback_s.lib order in callback test makefiles, as some toolchains are picky about order
- doc:
* man page updates to describe aggregate interface
* manual overview changes to highlight platforms with aggregate-by-value support
- test/plain: replaced tests w/ old/stale sctruct interface with new aggregate one
author | Tassilo Philipp |
---|---|
date | Thu, 21 Apr 2022 13:35:47 +0200 |
parents | ddfb9577a00e |
children | ba70fb631bea |
comparison
equal
deleted
inserted
replaced
532:d4bf63ab9164 | 533:71c884e610f0 |
---|---|
4 Library: dyncall | 4 Library: dyncall |
5 File: dyncall/dyncall_callvm_x64.c | 5 File: dyncall/dyncall_callvm_x64.c |
6 Description: | 6 Description: |
7 License: | 7 License: |
8 | 8 |
9 Copyright (c) 2007-2020 Daniel Adler <dadler@uni-goettingen.de>, | 9 Copyright (c) 2007-2022 Daniel Adler <dadler@uni-goettingen.de>, |
10 Tassilo Philipp <tphilipp@potion-studios.com> | 10 Tassilo Philipp <tphilipp@potion-studios.com> |
11 | 11 |
12 Permission to use, copy, modify, and distribute this software for any | 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 | 13 purpose with or without fee is hereby granted, provided that the above |
14 copyright notice and this permission notice appear in all copies. | 14 copyright notice and this permission notice appear in all copies. |
29 /* MS Windows x64 calling convention, AMD64 SystemV ABI. */ | 29 /* MS Windows x64 calling convention, AMD64 SystemV ABI. */ |
30 | 30 |
31 | 31 |
32 #include "dyncall_callvm_x64.h" | 32 #include "dyncall_callvm_x64.h" |
33 #include "dyncall_alloc.h" | 33 #include "dyncall_alloc.h" |
34 #include "dyncall_struct.h" | 34 #include "dyncall_aggregate.h" |
35 | |
36 #include <stdint.h> | |
37 #include <string.h> | |
38 #include <assert.h> | |
35 | 39 |
36 | 40 |
37 /* | 41 /* |
38 ** x64 SystemV calling convention | 42 ** x64 SystemV calling convention |
39 ** | 43 ** |
40 ** - hybrid return-type call (bool ... pointer) | 44 ** - hybrid return-type call (bool ... pointer) |
41 ** | 45 ** |
42 */ | 46 */ |
43 | 47 |
44 void dcCall_x64_sysv(DCsize stacksize, DCpointer stackdata, DCpointer regdata_i, DCpointer regdata_f, DCpointer target); | 48 #if defined(DC_UNIX) |
45 void dcCall_x64_win64(DCsize stacksize, DCpointer stackdata, DCpointer regdata, DCpointer target); | 49 extern void dcCall_x64_sysv(DCsize stacksize, DCpointer stackdata, DCpointer regdata_i, DCpointer regdata_f, DCpointer target); |
46 void dcCall_x64_syscall_sysv(DCpointer argdata, DCpointer target); | 50 extern void dcCall_x64_sysv_aggr(DCsize stacksize, DCpointer stackdata, DCpointer regdata_i, DCpointer regdata_f, DCpointer target, DCpointer ret_regs); |
51 #else | |
52 extern void dcCall_x64_win64(DCsize stacksize, DCpointer stackdata, DCpointer regdata, DCpointer target); | |
53 extern void dcCall_x64_win64_aggr(DCsize stacksize, DCpointer stackdata, DCpointer regdata, DCpointer target, DCpointer aggr_mem); | |
54 #endif | |
55 extern void dcCall_x64_syscall_sysv(DCpointer argdata, DCpointer target); | |
56 | |
57 | |
47 | 58 |
48 | 59 |
49 static void dc_callvm_free_x64(DCCallVM* in_self) | 60 static void dc_callvm_free_x64(DCCallVM* in_self) |
50 { | 61 { |
51 dcFreeMem(in_self); | 62 dcFreeMem(in_self); |
55 static void dc_callvm_reset_x64(DCCallVM* in_self) | 66 static void dc_callvm_reset_x64(DCCallVM* in_self) |
56 { | 67 { |
57 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | 68 DCCallVM_x64* self = (DCCallVM_x64*)in_self; |
58 dcVecReset(&self->mVecHead); | 69 dcVecReset(&self->mVecHead); |
59 self->mRegCount.i = self->mRegCount.f = 0; | 70 self->mRegCount.i = self->mRegCount.f = 0; |
60 } | 71 self->mAggrReturnReg = -1; |
72 #if defined(DC_WINDOWS) | |
73 self->mpAggrVecCopies = ((DCchar*)dcVecData(&self->mVecHead)) + self->mVecHead.mTotal; | |
74 #endif | |
75 } | |
76 | |
77 | |
61 | 78 |
62 | 79 |
63 static void dc_callvm_argLongLong_x64(DCCallVM* in_self, DClonglong x) | 80 static void dc_callvm_argLongLong_x64(DCCallVM* in_self, DClonglong x) |
64 { | 81 { |
65 /* A long long always has 64 bits on the supported x64 platforms (lp64 on unix and llp64 on windows). */ | 82 /* A long long always has 64 bits on the supported x64 platforms (lp64 on unix and llp64 on windows). */ |
66 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | 83 DCCallVM_x64* self = (DCCallVM_x64*)in_self; |
84 | |
85 self->mRegCount.i += (self->mRegCount.i == self->mAggrReturnReg); | |
86 | |
67 if(self->mRegCount.i < numIntRegs) | 87 if(self->mRegCount.i < numIntRegs) |
68 self->mRegData.i[self->mRegCount.i++] = x; | 88 self->mRegData.i[self->mRegCount.i++] = x; |
69 else | 89 else |
70 dcVecAppend(&self->mVecHead, &x, sizeof(DClonglong)); | 90 dcVecAppend(&self->mVecHead, &x, sizeof(DClonglong)); |
71 } | 91 } |
99 { | 119 { |
100 dc_callvm_argLongLong_x64(in_self, x); | 120 dc_callvm_argLongLong_x64(in_self, x); |
101 } | 121 } |
102 | 122 |
103 | 123 |
124 static void dc_callvm_argDouble_x64(DCCallVM* in_self, DCdouble x) | |
125 { | |
126 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
127 | |
128 #if defined(DC_WINDOWS) | |
129 self->mRegCount.f += (self->mRegCount.f == self->mAggrReturnReg); | |
130 #endif | |
131 | |
132 if(self->mRegCount.f < numFloatRegs) | |
133 self->mRegData.f[self->mRegCount.f++] = x; | |
134 else | |
135 dcVecAppend(&self->mVecHead, &x, sizeof(DCdouble)); | |
136 } | |
137 | |
138 | |
104 static void dc_callvm_argFloat_x64(DCCallVM* in_self, DCfloat x) | 139 static void dc_callvm_argFloat_x64(DCCallVM* in_self, DCfloat x) |
105 { | 140 { |
106 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
107 | |
108 /* Although not promoted to doubles, floats are stored with 64bits in this API.*/ | 141 /* Although not promoted to doubles, floats are stored with 64bits in this API.*/ |
109 union { | 142 union { |
110 DCdouble d; | 143 DCdouble d; |
111 DCfloat f; | 144 DCfloat f; |
112 } f; | 145 } f; |
113 f.f = x; | 146 f.f = x; |
114 | 147 |
115 if(self->mRegCount.f < numFloatRegs) | 148 dc_callvm_argDouble_x64(in_self, f.d); |
116 *(DCfloat*)&self->mRegData.f[self->mRegCount.f++] = x; | |
117 else | |
118 dcVecAppend(&self->mVecHead, &f.f, sizeof(DCdouble)); | |
119 } | |
120 | |
121 | |
122 static void dc_callvm_argDouble_x64(DCCallVM* in_self, DCdouble x) | |
123 { | |
124 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
125 if(self->mRegCount.f < numFloatRegs) | |
126 self->mRegData.f[self->mRegCount.f++] = x; | |
127 else | |
128 dcVecAppend(&self->mVecHead, &x, sizeof(DCdouble)); | |
129 } | 149 } |
130 | 150 |
131 | 151 |
132 static void dc_callvm_argPointer_x64(DCCallVM* in_self, DCpointer x) | 152 static void dc_callvm_argPointer_x64(DCCallVM* in_self, DCpointer x) |
133 { | 153 { |
134 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | 154 DCCallVM_x64* self = (DCCallVM_x64*)in_self; |
155 | |
156 self->mRegCount.i += (self->mRegCount.i == self->mAggrReturnReg); | |
157 | |
135 if(self->mRegCount.i < numIntRegs) | 158 if(self->mRegCount.i < numIntRegs) |
136 *(DCpointer*)&self->mRegData.i[self->mRegCount.i++] = x; | 159 *(DCpointer*)&self->mRegData.i[self->mRegCount.i++] = x; |
137 else | 160 else |
138 dcVecAppend(&self->mVecHead, &x, sizeof(DCpointer)); | 161 dcVecAppend(&self->mVecHead, &x, sizeof(DCpointer)); |
139 } | 162 } |
140 | 163 |
141 static void dc_callvm_argStruct_x64(DCCallVM* in_self, DCstruct* s, DCpointer x) | 164 |
142 { | 165 static void dc_callvm_argAggr_x64(DCCallVM* in_self, const DCaggr* ag, const void* x) |
143 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | 166 { |
144 dcVecAppend(&self->mVecHead, x, s->size); | 167 int i; |
145 /*printf("dc_callvm_argStruct_x64 size = %d\n", (int)s->size);@@@*/ | 168 DCCallVM_x64* self = (DCCallVM_x64*)in_self; |
146 if (s->size <= 64) | 169 |
147 dcArgStructUnroll(in_self, s, x); | 170 if (!ag) { |
148 /*else@@@*/ | 171 /* non-trivial aggrs (C++) are passed via pointer (win and sysv callconv), |
149 /* dcVecAppend(&self->mVecHead, &x, sizeof(DCpointer));@@@*/ | 172 * copy has to be provided by user, as dyncall cannot do such copies*/ |
173 dc_callvm_argPointer_x64(in_self, (DCpointer)x); | |
174 return; | |
175 } | |
176 | |
177 #if defined(DC_UNIX) | |
178 DCRegCount_x64 n_regs = { self->mRegCount.i, self->mRegCount.f }; | |
179 | |
180 if(ag->sysv_classes[0] != SYSVC_MEMORY) { | |
181 /* reclassify aggr w/ respect to remaining regs, might need to pass it all via the stack */ | |
182 for(i=0; ag->sysv_classes[i] && i<DC_SYSV_MAX_NUM_CLASSES; ++i) { | |
183 DCuchar clz = ag->sysv_classes[i]; | |
184 n_regs.i += (clz == SYSVC_INTEGER); | |
185 n_regs.f += (clz == SYSVC_SSE); | |
186 /* @@@AGGR implement when implementing x87 types */ | |
187 } | |
188 } | |
189 | |
190 if(ag->sysv_classes[0] == SYSVC_MEMORY || (n_regs.i > numIntRegs) || (n_regs.f > numFloatRegs)) | |
191 { | |
192 dcVecAppend(&self->mVecHead, x, ag->size); | |
193 dcVecSkip(&self->mVecHead, (ag->size + (sizeof(DClonglong)-1) & -sizeof(DClonglong)) - ag->size); /* realign to qword */ | |
194 return; | |
195 } | |
196 | |
197 for(i=0; ag->sysv_classes[i] && i<DC_SYSV_MAX_NUM_CLASSES; ++i) | |
198 { | |
199 switch (ag->sysv_classes[i]) { | |
200 case SYSVC_INTEGER: dc_callvm_argLongLong_x64(in_self, ((DClonglong*)x)[i]); break; | |
201 case SYSVC_SSE: dc_callvm_argDouble_x64 (in_self, ((DCdouble *)x)[i]); break; | |
202 /* @@@AGGR implement when implementing x87 types */ | |
203 } | |
204 } | |
205 | |
206 #else | |
207 | |
208 switch (ag->size) { | |
209 case 1: dc_callvm_argChar_x64 (in_self, *(DCchar *)x); break; | |
210 case 2: dc_callvm_argShort_x64 (in_self, *(DCshort *)x); break; | |
211 case 4: dc_callvm_argLong_x64 (in_self, *(DClong *)x); break; | |
212 case 8: dc_callvm_argLongLong_x64(in_self, *(DClonglong*)x); break; | |
213 default: | |
214 /* pass the aggr indirectly via hidden pointer; requires caller-made copy | |
215 * to mimic pass-by-value semantics (or a call that modifies the param | |
216 * would corrupt the source aggr) | |
217 * place those copies at the end of the param vector (aligned to 16b for | |
218 * this calling convention); it's a bit of a hack, but should be safe: in | |
219 * any case the vector has to be big enough to hold all params */ | |
220 self->mpAggrVecCopies = (void*)((intptr_t)((DCchar*)self->mpAggrVecCopies - ag->size) & -16); | |
221 x = memcpy(self->mpAggrVecCopies, x, ag->size); | |
222 dc_callvm_argPointer_x64(in_self, (DCpointer)x); | |
223 break; | |
224 } | |
225 #endif | |
150 } | 226 } |
151 | 227 |
152 | 228 |
153 /* Call. */ | 229 /* Call. */ |
154 void dc_callvm_call_x64(DCCallVM* in_self, DCpointer target) | 230 static void dc_callvm_call_x64(DCCallVM* in_self, DCpointer target) |
155 { | 231 { |
156 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | 232 DCCallVM_x64* self = (DCCallVM_x64*)in_self; |
157 #if defined(DC_UNIX) | 233 #if defined(DC_UNIX) |
158 dcCall_x64_sysv( | 234 dcCall_x64_sysv( |
159 #else | 235 #else |
165 #if defined(DC_UNIX) | 241 #if defined(DC_UNIX) |
166 self->mRegData.f, /* Pointer to floating point register arguments. */ | 242 self->mRegData.f, /* Pointer to floating point register arguments. */ |
167 #endif | 243 #endif |
168 target | 244 target |
169 ); | 245 ); |
246 } | |
247 | |
248 | |
249 static void dc_callvm_begin_aggr_x64(DCCallVM* in_self, const DCaggr *ag) | |
250 { | |
251 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
252 | |
253 assert(self->mRegCount.i == 0 && self->mRegCount.f == 0 && "dc_callvm_begin_aggr_x64 should be called before any function arguments are declared"); | |
254 #if defined(DC_UNIX) | |
255 if (!ag || (ag->sysv_classes[0] == SYSVC_MEMORY)) { | |
256 #else | |
257 if (!ag || ag->size > 8) { | |
258 #endif | |
259 /* pass pointer to aggregate as hidden first argument */ | |
260 self->mAggrReturnReg = 0; | |
261 } | |
262 } | |
263 | |
264 | |
265 #if defined(DC_WINDOWS) | |
266 static void dc_callvm_begin_aggr_x64_win64_this(DCCallVM* in_self, const DCaggr *ag) | |
267 { | |
268 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
269 | |
270 assert(self->mRegCount.i == 0 && self->mRegCount.f == 0 && "dc_callvm_begin_aggr_x64_win64_this should be called before any function arguments are declared"); | |
271 | |
272 if (!ag || ag->size > 8) { | |
273 /* thiscall: this-ptr comes first, then pointer to aggregate as hidden (second) argument */ | |
274 self->mAggrReturnReg = 1; | |
275 } | |
276 } | |
277 #endif | |
278 | |
279 | |
280 static void dc_callvm_call_x64_aggr(DCCallVM* in_self, DCpointer target, const DCaggr *ag, DCpointer ret) | |
281 { | |
282 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
283 | |
284 #if defined(DC_UNIX) | |
285 | |
286 if (self->mAggrReturnReg != -1) { | |
287 /* call regular dcCall_x64_sysv here, w/ pointer to the aggr in first arg */ | |
288 self->mRegData.i[self->mAggrReturnReg] = (int64)ret; | |
289 | |
290 dcCall_x64_sysv( | |
291 dcVecSize(&self->mVecHead), /* rdi: Size of stack data. */ | |
292 dcVecData(&self->mVecHead), /* rsi: Pointer to stack arguments. */ | |
293 self->mRegData.i, /* rdx: Pointer to register arguments (ints on SysV). */ | |
294 self->mRegData.f, /* rcx: Pointer to floating point register arguments. */ | |
295 target /* r8 */ | |
296 ); | |
297 } else { | |
298 int i; | |
299 DCchar ret_regs[32]; /* 4 qwords: 2 for ints, 2 for floats */ | |
300 DCchar *ret_regs_i = ret_regs+0; | |
301 DCchar *ret_regs_f = ret_regs+16; | |
302 DCsize st_size = ag->size; | |
303 DCchar* dst = (char*)ret; | |
304 dcCall_x64_sysv_aggr( | |
305 dcVecSize(&self->mVecHead), /* rdi: Size of stack data. */ | |
306 dcVecData(&self->mVecHead), /* rsi: Pointer to stack arguments. */ | |
307 self->mRegData.i, /* rdx: Pointer to register arguments (ints on SysV). */ | |
308 self->mRegData.f, /* rcx: Pointer to floating point register arguments. */ | |
309 target, /* r8 */ | |
310 ret_regs /* r9 */ | |
311 ); | |
312 /* reassemble aggr to be returned from reg data */ | |
313 for(i=0; ag->sysv_classes[i] && i<DC_SYSV_MAX_NUM_CLASSES; ++i) { | |
314 DCchar** src; | |
315 int ll = 8; | |
316 switch(ag->sysv_classes[i]) { | |
317 case SYSVC_INTEGER: src = &ret_regs_i; break; | |
318 case SYSVC_SSE: src = &ret_regs_f; break; | |
319 /* @@@AGGR implement when implementing x87 types */ | |
320 } | |
321 while(ll-- && st_size--) | |
322 *dst++ = *(*src)++; | |
323 } | |
324 } | |
325 | |
326 #else | |
327 | |
328 if (self->mAggrReturnReg != -1) { | |
329 /* call regular dcCall_x64_sysv here, w/ pointer to the aggr in first arg */ | |
330 self->mRegData.i[self->mAggrReturnReg] = (int64)ret; | |
331 | |
332 dcCall_x64_win64( | |
333 dcVecSize(&self->mVecHead), /* rcx: Size of stack data. */ | |
334 dcVecData(&self->mVecHead), /* rdx: Pointer to stack arguments. */ | |
335 self->mRegData.i, /* r8: Pointer to register arguments */ | |
336 target /* r9 */ | |
337 ); | |
338 } else { | |
339 DCchar ret_reg[8]; /* 1 qword */ | |
340 DCsize st_size = ag->size; /* guaranteed to be <= 8 */ | |
341 DCchar* dst = (char*)ret; | |
342 DCchar* src = ret_reg; | |
343 dcCall_x64_win64_aggr( | |
344 dcVecSize(&self->mVecHead), /* rcx: Size of stack data. */ | |
345 dcVecData(&self->mVecHead), /* rdx: Pointer to stack arguments. */ | |
346 self->mRegData.i, /* r8: Pointer to register arguments */ | |
347 target, /* r9 */ | |
348 ret_reg /* stack */ | |
349 ); | |
350 while(st_size--) | |
351 *dst++ = *src++; | |
352 } | |
353 | |
354 #endif | |
170 } | 355 } |
171 | 356 |
172 | 357 |
173 static void dc_callvm_mode_x64(DCCallVM* in_self, DCint mode); | 358 static void dc_callvm_mode_x64(DCCallVM* in_self, DCint mode); |
174 | 359 |
184 , &dc_callvm_argLong_x64 | 369 , &dc_callvm_argLong_x64 |
185 , &dc_callvm_argLongLong_x64 | 370 , &dc_callvm_argLongLong_x64 |
186 , &dc_callvm_argFloat_x64 | 371 , &dc_callvm_argFloat_x64 |
187 , &dc_callvm_argDouble_x64 | 372 , &dc_callvm_argDouble_x64 |
188 , &dc_callvm_argPointer_x64 | 373 , &dc_callvm_argPointer_x64 |
189 , &dc_callvm_argStruct_x64 | 374 , &dc_callvm_argAggr_x64 |
190 , (DCvoidvmfunc*) &dc_callvm_call_x64 | 375 , (DCvoidvmfunc*) &dc_callvm_call_x64 |
191 , (DCboolvmfunc*) &dc_callvm_call_x64 | 376 , (DCboolvmfunc*) &dc_callvm_call_x64 |
192 , (DCcharvmfunc*) &dc_callvm_call_x64 | 377 , (DCcharvmfunc*) &dc_callvm_call_x64 |
193 , (DCshortvmfunc*) &dc_callvm_call_x64 | 378 , (DCshortvmfunc*) &dc_callvm_call_x64 |
194 , (DCintvmfunc*) &dc_callvm_call_x64 | 379 , (DCintvmfunc*) &dc_callvm_call_x64 |
195 , (DClongvmfunc*) &dc_callvm_call_x64 | 380 , (DClongvmfunc*) &dc_callvm_call_x64 |
196 , (DClonglongvmfunc*) &dc_callvm_call_x64 | 381 , (DClonglongvmfunc*) &dc_callvm_call_x64 |
197 , (DCfloatvmfunc*) &dc_callvm_call_x64 | 382 , (DCfloatvmfunc*) &dc_callvm_call_x64 |
198 , (DCdoublevmfunc*) &dc_callvm_call_x64 | 383 , (DCdoublevmfunc*) &dc_callvm_call_x64 |
199 , (DCpointervmfunc*) &dc_callvm_call_x64 | 384 , (DCpointervmfunc*) &dc_callvm_call_x64 |
200 , NULL /* callStruct */ | 385 , (DCaggrvmfunc*) &dc_callvm_call_x64_aggr |
386 , (DCbeginaggrvmfunc*)&dc_callvm_begin_aggr_x64 | |
201 }; | 387 }; |
202 | 388 |
203 | 389 |
204 /* --- syscall ------------------------------------------------------------- */ | 390 #if defined(DC_WINDOWS) |
205 | 391 /* --- win64 thiscalls ------------------------------------------------------------- */ |
206 #include <assert.h> | 392 |
207 void dc_callvm_call_x64_syscall_sysv(DCCallVM* in_self, DCpointer target) | 393 DCCallVM_vt gVT_x64_win64_this = |
208 { | |
209 DCCallVM_x64* self; | |
210 | |
211 /* syscalls can have up to 6 args, required to be "Only values of class INTEGER or class MEMORY" (from */ | |
212 /* SysV manual), so we can use self->mRegData.i directly; verify this has space for at least 6 values, though. */ | |
213 assert(numIntRegs >= 6); | |
214 | |
215 self = (DCCallVM_x64*)in_self; | |
216 dcCall_x64_syscall_sysv(self->mRegData.i, target); | |
217 } | |
218 | |
219 DCCallVM_vt gVT_x64_syscall_sysv = | |
220 { | 394 { |
221 &dc_callvm_free_x64 | 395 &dc_callvm_free_x64 |
222 , &dc_callvm_reset_x64 | 396 , &dc_callvm_reset_x64 |
223 , &dc_callvm_mode_x64 | 397 , &dc_callvm_mode_x64 |
224 , &dc_callvm_argBool_x64 | 398 , &dc_callvm_argBool_x64 |
228 , &dc_callvm_argLong_x64 | 402 , &dc_callvm_argLong_x64 |
229 , &dc_callvm_argLongLong_x64 | 403 , &dc_callvm_argLongLong_x64 |
230 , &dc_callvm_argFloat_x64 | 404 , &dc_callvm_argFloat_x64 |
231 , &dc_callvm_argDouble_x64 | 405 , &dc_callvm_argDouble_x64 |
232 , &dc_callvm_argPointer_x64 | 406 , &dc_callvm_argPointer_x64 |
233 , NULL /* argStruct */ | 407 , &dc_callvm_argAggr_x64 |
408 , (DCvoidvmfunc*) &dc_callvm_call_x64 | |
409 , (DCboolvmfunc*) &dc_callvm_call_x64 | |
410 , (DCcharvmfunc*) &dc_callvm_call_x64 | |
411 , (DCshortvmfunc*) &dc_callvm_call_x64 | |
412 , (DCintvmfunc*) &dc_callvm_call_x64 | |
413 , (DClongvmfunc*) &dc_callvm_call_x64 | |
414 , (DClonglongvmfunc*) &dc_callvm_call_x64 | |
415 , (DCfloatvmfunc*) &dc_callvm_call_x64 | |
416 , (DCdoublevmfunc*) &dc_callvm_call_x64 | |
417 , (DCpointervmfunc*) &dc_callvm_call_x64 | |
418 , (DCaggrvmfunc*) &dc_callvm_call_x64_aggr | |
419 , (DCbeginaggrvmfunc*)&dc_callvm_begin_aggr_x64_win64_this | |
420 }; | |
421 | |
422 #endif | |
423 | |
424 /* --- syscall ------------------------------------------------------------- */ | |
425 | |
426 #if defined(DC_UNIX) | |
427 void dc_callvm_call_x64_syscall_sysv(DCCallVM* in_self, DCpointer target) | |
428 { | |
429 DCCallVM_x64* self; | |
430 | |
431 /* syscalls can have up to 6 args, required to be "Only values of class INTEGER or class MEMORY" (from */ | |
432 /* SysV manual), so we can use self->mRegData.i directly; verify this has space for at least 6 values, though. */ | |
433 assert(numIntRegs >= 6); | |
434 | |
435 self = (DCCallVM_x64*)in_self; | |
436 dcCall_x64_syscall_sysv(self->mRegData.i, target); | |
437 } | |
438 | |
439 DCCallVM_vt gVT_x64_syscall_sysv = | |
440 { | |
441 &dc_callvm_free_x64 | |
442 , &dc_callvm_reset_x64 | |
443 , &dc_callvm_mode_x64 | |
444 , &dc_callvm_argBool_x64 | |
445 , &dc_callvm_argChar_x64 | |
446 , &dc_callvm_argShort_x64 | |
447 , &dc_callvm_argInt_x64 | |
448 , &dc_callvm_argLong_x64 | |
449 , &dc_callvm_argLongLong_x64 | |
450 , &dc_callvm_argFloat_x64 | |
451 , &dc_callvm_argDouble_x64 | |
452 , &dc_callvm_argPointer_x64 | |
453 , NULL /* argAggr */ | |
234 , (DCvoidvmfunc*) &dc_callvm_call_x64_syscall_sysv | 454 , (DCvoidvmfunc*) &dc_callvm_call_x64_syscall_sysv |
235 , (DCboolvmfunc*) &dc_callvm_call_x64_syscall_sysv | 455 , (DCboolvmfunc*) &dc_callvm_call_x64_syscall_sysv |
236 , (DCcharvmfunc*) &dc_callvm_call_x64_syscall_sysv | 456 , (DCcharvmfunc*) &dc_callvm_call_x64_syscall_sysv |
237 , (DCshortvmfunc*) &dc_callvm_call_x64_syscall_sysv | 457 , (DCshortvmfunc*) &dc_callvm_call_x64_syscall_sysv |
238 , (DCintvmfunc*) &dc_callvm_call_x64_syscall_sysv | 458 , (DCintvmfunc*) &dc_callvm_call_x64_syscall_sysv |
239 , (DClongvmfunc*) &dc_callvm_call_x64_syscall_sysv | 459 , (DClongvmfunc*) &dc_callvm_call_x64_syscall_sysv |
240 , (DClonglongvmfunc*) &dc_callvm_call_x64_syscall_sysv | 460 , (DClonglongvmfunc*) &dc_callvm_call_x64_syscall_sysv |
241 , (DCfloatvmfunc*) &dc_callvm_call_x64_syscall_sysv | 461 , (DCfloatvmfunc*) &dc_callvm_call_x64_syscall_sysv |
242 , (DCdoublevmfunc*) &dc_callvm_call_x64_syscall_sysv | 462 , (DCdoublevmfunc*) &dc_callvm_call_x64_syscall_sysv |
243 , (DCpointervmfunc*) &dc_callvm_call_x64_syscall_sysv | 463 , (DCpointervmfunc*) &dc_callvm_call_x64_syscall_sysv |
244 , NULL /* callStruct */ | 464 , NULL /* callAggr */ |
465 , NULL /* beginAggr */ | |
245 }; | 466 }; |
467 #endif | |
246 | 468 |
247 | 469 |
248 | 470 |
249 /* mode */ | 471 /* mode */ |
250 | 472 |
253 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | 475 DCCallVM_x64* self = (DCCallVM_x64*)in_self; |
254 DCCallVM_vt* vt; | 476 DCCallVM_vt* vt; |
255 | 477 |
256 switch(mode) { | 478 switch(mode) { |
257 case DC_CALL_C_DEFAULT: | 479 case DC_CALL_C_DEFAULT: |
258 case DC_CALL_C_DEFAULT_THIS: | 480 #if defined(DC_UNIX) |
259 #if defined(DC_UNIX) | 481 case DC_CALL_C_DEFAULT_THIS: |
260 case DC_CALL_C_X64_SYSV: | 482 case DC_CALL_C_X64_SYSV: /* = DC_CALL_C_X64_SYSV_THIS */ |
261 #else | 483 #else |
262 case DC_CALL_C_X64_WIN64: | 484 case DC_CALL_C_X64_WIN64: |
263 #endif | 485 #endif |
264 case DC_CALL_C_ELLIPSIS: | 486 case DC_CALL_C_ELLIPSIS: |
265 case DC_CALL_C_ELLIPSIS_VARARGS: | 487 case DC_CALL_C_ELLIPSIS_VARARGS: |
266 vt = &gVT_x64; | 488 vt = &gVT_x64; |
267 break; | 489 break; |
490 #if defined(DC_WINDOWS) | |
491 case DC_CALL_C_DEFAULT_THIS: | |
492 case DC_CALL_C_X64_WIN64_THIS: | |
493 vt = &gVT_x64_win64_this; | |
494 break; | |
495 #endif | |
268 case DC_CALL_SYS_DEFAULT: | 496 case DC_CALL_SYS_DEFAULT: |
269 #if defined(DC_UNIX) | 497 #if defined(DC_UNIX) |
270 case DC_CALL_SYS_X64_SYSCALL_SYSV: | 498 case DC_CALL_SYS_X64_SYSCALL_SYSV: |
271 vt = &gVT_x64_syscall_sysv; break; | 499 vt = &gVT_x64_syscall_sysv; break; |
272 #else | 500 #else |