Mercurial > pub > dyncall > dyncall
annotate dyncall/dyncall_callvm_x64.c @ 366:ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
author | Tassilo Philipp |
---|---|
date | Wed, 15 Apr 2020 14:57:23 +0200 |
parents | a2a42f477662 |
children | ddfb9577a00e |
rev | line source |
---|---|
0 | 1 /* |
2 | |
3 Package: dyncall | |
4 Library: dyncall | |
5 File: dyncall/dyncall_callvm_x64.c | |
6 Description: | |
7 License: | |
8 | |
339 | 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 | |
27 | |
28 | |
29 /* MS Windows x64 calling convention, AMD64 SystemV ABI. */ | |
30 | |
31 | |
32 #include "dyncall_callvm_x64.h" | |
33 #include "dyncall_alloc.h" | |
34 #include "dyncall_struct.h" | |
35 | |
36 | |
366
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
37 /* |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
38 ** x64 SystemV calling convention |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
39 ** |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
40 ** - hybrid return-type call (bool ... pointer) |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
41 ** |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
42 */ |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
43 |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
44 void dcCall_x64_sysv(DCsize stacksize, DCpointer stackdata, DCpointer regdata_i, DCpointer regdata_f, DCpointer target); |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
45 void dcCall_x64_win64(DCsize stacksize, DCpointer stackdata, DCpointer regdata, DCpointer target); |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
46 void dcCall_x64_syscall_sysv(DCpointer argdata, DCpointer target); |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
47 |
ad5f9803f52f
- removal of some unnecessary headers that only contained internally used forward declarations, so no need to have them
Tassilo Philipp
parents:
347
diff
changeset
|
48 |
0 | 49 static void dc_callvm_free_x64(DCCallVM* in_self) |
50 { | |
51 dcFreeMem(in_self); | |
52 } | |
53 | |
54 | |
55 static void dc_callvm_reset_x64(DCCallVM* in_self) | |
56 { | |
57 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
58 dcVecReset(&self->mVecHead); | |
84 | 59 self->mRegCount.i = self->mRegCount.f = 0; |
0 | 60 } |
61 | |
62 | |
63 static void dc_callvm_argLongLong_x64(DCCallVM* in_self, DClonglong x) | |
64 { | |
65 /* 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; | |
67 if(self->mRegCount.i < numIntRegs) | |
68 self->mRegData.i[self->mRegCount.i++] = x; | |
69 else | |
70 dcVecAppend(&self->mVecHead, &x, sizeof(DClonglong)); | |
71 } | |
72 | |
73 | |
74 static void dc_callvm_argBool_x64(DCCallVM* in_self, DCbool x) | |
75 { | |
76 dc_callvm_argLongLong_x64(in_self, (DClonglong)x); | |
77 } | |
78 | |
79 | |
80 static void dc_callvm_argChar_x64(DCCallVM* in_self, DCchar x) | |
81 { | |
82 dc_callvm_argLongLong_x64(in_self, x); | |
83 } | |
84 | |
85 | |
86 static void dc_callvm_argShort_x64(DCCallVM* in_self, DCshort x) | |
87 { | |
88 dc_callvm_argLongLong_x64(in_self, x); | |
89 } | |
90 | |
91 | |
92 static void dc_callvm_argInt_x64(DCCallVM* in_self, DCint x) | |
93 { | |
94 dc_callvm_argLongLong_x64(in_self, x); | |
95 } | |
96 | |
97 | |
98 static void dc_callvm_argLong_x64(DCCallVM* in_self, DClong x) | |
99 { | |
100 dc_callvm_argLongLong_x64(in_self, x); | |
101 } | |
102 | |
103 | |
104 static void dc_callvm_argFloat_x64(DCCallVM* in_self, DCfloat x) | |
105 { | |
106 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
107 | |
108 /* Although not promoted to doubles, floats are stored with 64bits in this API.*/ | |
109 union { | |
110 DCdouble d; | |
111 DCfloat f; | |
112 } f; | |
113 f.f = x; | |
114 | |
115 if(self->mRegCount.f < numFloatRegs) | |
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 } | |
130 | |
131 | |
132 static void dc_callvm_argPointer_x64(DCCallVM* in_self, DCpointer x) | |
133 { | |
134 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
135 if(self->mRegCount.i < numIntRegs) | |
136 *(DCpointer*)&self->mRegData.i[self->mRegCount.i++] = x; | |
137 else | |
138 dcVecAppend(&self->mVecHead, &x, sizeof(DCpointer)); | |
139 } | |
140 | |
141 static void dc_callvm_argStruct_x64(DCCallVM* in_self, DCstruct* s, DCpointer x) | |
142 { | |
143 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
144 dcVecAppend(&self->mVecHead, x, s->size); | |
145 /*printf("dc_callvm_argStruct_x64 size = %d\n", (int)s->size);@@@*/ | |
146 if (s->size <= 64) | |
147 dcArgStructUnroll(in_self, s, x); | |
148 /*else@@@*/ | |
149 /* dcVecAppend(&self->mVecHead, &x, sizeof(DCpointer));@@@*/ | |
150 } | |
151 | |
152 | |
153 /* Call. */ | |
154 void dc_callvm_call_x64(DCCallVM* in_self, DCpointer target) | |
155 { | |
156 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
157 #if defined(DC_UNIX) | |
158 dcCall_x64_sysv( | |
159 #else | |
160 dcCall_x64_win64( | |
161 #endif | |
162 dcVecSize(&self->mVecHead), /* Size of stack data. */ | |
163 dcVecData(&self->mVecHead), /* Pointer to stack arguments. */ | |
164 self->mRegData.i, /* Pointer to register arguments (ints on SysV). */ | |
165 #if defined(DC_UNIX) | |
166 self->mRegData.f, /* Pointer to floating point register arguments. */ | |
167 #endif | |
168 target | |
169 ); | |
170 } | |
171 | |
172 | |
84 | 173 static void dc_callvm_mode_x64(DCCallVM* in_self, DCint mode); |
174 | |
0 | 175 DCCallVM_vt gVT_x64 = |
176 { | |
177 &dc_callvm_free_x64 | |
178 , &dc_callvm_reset_x64 | |
179 , &dc_callvm_mode_x64 | |
180 , &dc_callvm_argBool_x64 | |
181 , &dc_callvm_argChar_x64 | |
339 | 182 , &dc_callvm_argShort_x64 |
0 | 183 , &dc_callvm_argInt_x64 |
184 , &dc_callvm_argLong_x64 | |
185 , &dc_callvm_argLongLong_x64 | |
186 , &dc_callvm_argFloat_x64 | |
187 , &dc_callvm_argDouble_x64 | |
188 , &dc_callvm_argPointer_x64 | |
189 , &dc_callvm_argStruct_x64 | |
190 , (DCvoidvmfunc*) &dc_callvm_call_x64 | |
191 , (DCboolvmfunc*) &dc_callvm_call_x64 | |
192 , (DCcharvmfunc*) &dc_callvm_call_x64 | |
193 , (DCshortvmfunc*) &dc_callvm_call_x64 | |
194 , (DCintvmfunc*) &dc_callvm_call_x64 | |
195 , (DClongvmfunc*) &dc_callvm_call_x64 | |
196 , (DClonglongvmfunc*) &dc_callvm_call_x64 | |
197 , (DCfloatvmfunc*) &dc_callvm_call_x64 | |
198 , (DCdoublevmfunc*) &dc_callvm_call_x64 | |
199 , (DCpointervmfunc*) &dc_callvm_call_x64 | |
200 , NULL /* callStruct */ | |
201 }; | |
202 | |
339 | 203 |
204 /* --- syscall ------------------------------------------------------------- */ | |
205 | |
206 #include <assert.h> | |
341 | 207 void dc_callvm_call_x64_syscall_sysv(DCCallVM* in_self, DCpointer target) |
339 | 208 { |
347 | 209 DCCallVM_x64* self; |
210 | |
339 | 211 /* syscalls can have up to 6 args, required to be "Only values of class INTEGER or class MEMORY" (from */ |
347 | 212 /* SysV manual), so we can use self->mRegData.i directly; verify this has space for at least 6 values, though. */ |
339 | 213 assert(numIntRegs >= 6); |
214 | |
347 | 215 self = (DCCallVM_x64*)in_self; |
341 | 216 dcCall_x64_syscall_sysv(self->mRegData.i, target); |
339 | 217 } |
218 | |
341 | 219 DCCallVM_vt gVT_x64_syscall_sysv = |
339 | 220 { |
221 &dc_callvm_free_x64 | |
222 , &dc_callvm_reset_x64 | |
223 , &dc_callvm_mode_x64 | |
224 , &dc_callvm_argBool_x64 | |
225 , &dc_callvm_argChar_x64 | |
226 , &dc_callvm_argShort_x64 | |
227 , &dc_callvm_argInt_x64 | |
228 , &dc_callvm_argLong_x64 | |
229 , &dc_callvm_argLongLong_x64 | |
230 , &dc_callvm_argFloat_x64 | |
231 , &dc_callvm_argDouble_x64 | |
232 , &dc_callvm_argPointer_x64 | |
233 , NULL /* argStruct */ | |
341 | 234 , (DCvoidvmfunc*) &dc_callvm_call_x64_syscall_sysv |
235 , (DCboolvmfunc*) &dc_callvm_call_x64_syscall_sysv | |
236 , (DCcharvmfunc*) &dc_callvm_call_x64_syscall_sysv | |
237 , (DCshortvmfunc*) &dc_callvm_call_x64_syscall_sysv | |
238 , (DCintvmfunc*) &dc_callvm_call_x64_syscall_sysv | |
239 , (DClongvmfunc*) &dc_callvm_call_x64_syscall_sysv | |
240 , (DClonglongvmfunc*) &dc_callvm_call_x64_syscall_sysv | |
241 , (DCfloatvmfunc*) &dc_callvm_call_x64_syscall_sysv | |
242 , (DCdoublevmfunc*) &dc_callvm_call_x64_syscall_sysv | |
243 , (DCpointervmfunc*) &dc_callvm_call_x64_syscall_sysv | |
339 | 244 , NULL /* callStruct */ |
245 }; | |
246 | |
247 | |
248 | |
249 /* mode */ | |
250 | |
84 | 251 static void dc_callvm_mode_x64(DCCallVM* in_self, DCint mode) |
252 { | |
253 DCCallVM_x64* self = (DCCallVM_x64*)in_self; | |
254 DCCallVM_vt* vt; | |
0 | 255 |
84 | 256 switch(mode) { |
257 case DC_CALL_C_DEFAULT: | |
258 #if defined(DC_UNIX) | |
259 case DC_CALL_C_X64_SYSV: | |
260 #else | |
261 case DC_CALL_C_X64_WIN64: | |
262 #endif | |
263 case DC_CALL_C_ELLIPSIS: | |
264 case DC_CALL_C_ELLIPSIS_VARARGS: | |
265 vt = &gVT_x64; | |
266 break; | |
339 | 267 case DC_CALL_SYS_DEFAULT: |
268 # if defined DC_UNIX | |
269 case DC_CALL_SYS_X64_SYSCALL_SYSV: | |
341 | 270 vt = &gVT_x64_syscall_sysv; break; |
339 | 271 # else |
272 self->mInterface.mError = DC_ERROR_UNSUPPORTED_MODE; return; | |
273 # endif | |
84 | 274 default: |
275 self->mInterface.mError = DC_ERROR_UNSUPPORTED_MODE; | |
276 return; | |
277 } | |
278 dc_callvm_base_init(&self->mInterface, vt); | |
0 | 279 } |
280 | |
84 | 281 /* Public API. */ |
0 | 282 DCCallVM* dcNewCallVM(DCsize size) |
283 { | |
84 | 284 DCCallVM_x64* p = (DCCallVM_x64*)dcAllocMem(sizeof(DCCallVM_x64)+size); |
285 | |
286 dc_callvm_mode_x64((DCCallVM*)p, DC_CALL_C_DEFAULT); | |
287 | |
288 /* Since we store register parameters in DCCallVM_x64 directly, adjust the stack size. */ | |
289 size -= sizeof(DCRegData_x64); | |
290 size = (((signed long)size) < 0) ? 0 : size; | |
291 dcVecInit(&p->mVecHead, size); | |
292 dc_callvm_reset_x64((DCCallVM*)p); | |
293 | |
294 return (DCCallVM*)p; | |
0 | 295 } |
296 |