Fixed THISCALL/FASTCALL closures and added basic support for PASCAL/REGISTER closures.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
diff --git a/src/x86/ffi.c b/src/x86/ffi.c
index 1dd00eb..cb5f634 100644
--- a/src/x86/ffi.c
+++ b/src/x86/ffi.c
@@ -419,6 +419,8 @@ void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
__attribute__ ((regparm(1)));
unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
__attribute__ ((regparm(1)));
+unsigned int FFI_HIDDEN ffi_closure_WIN32_inner (ffi_closure *, void **, void *)
+ __attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
__attribute__ ((regparm(1)));
#ifdef X86_WIN32
@@ -426,12 +428,10 @@ void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
__attribute__ ((regparm(1)));
#endif
#ifndef X86_WIN64
-void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
- __attribute__ ((regparm(1)));
-void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *)
- __attribute__ ((regparm(1)));
-void FFI_HIDDEN ffi_closure_FASTCALL (ffi_closure *)
- __attribute__ ((regparm(1)));
+void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *);
+void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *);
+void FFI_HIDDEN ffi_closure_FASTCALL (ffi_closure *);
+void FFI_HIDDEN ffi_closure_REGISTER (ffi_closure *);
#else
void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
#endif
@@ -490,6 +490,29 @@ ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
return cif->flags;
}
+
+unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
+ffi_closure_WIN32_inner (ffi_closure *closure, void **respp, void *args)
+{
+ /* our various things... */
+ ffi_cif *cif;
+ void **arg_area;
+
+ cif = closure->cif;
+ arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+
+ /* this call will initialize ARG_AREA, such that each
+ * element in that array points to the corresponding
+ * value on the stack; and if the function returns
+ * a structure, it will change RESP to point to the
+ * structure return address. */
+
+ ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
+
+ (closure->fun) (cif, *respp, arg_area, closure->user_data);
+
+ return cif->bytes;
+}
#endif /* !X86_WIN64 */
static void
@@ -587,7 +610,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
unsigned int __dis = __fun - (__ctx + 10); \
*(unsigned char*) &__tramp[0] = 0xb8; \
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
- *(unsigned char *) &__tramp[5] = 0xe9; \
+ *(unsigned char*) &__tramp[5] = 0xe9; \
*(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
}
@@ -618,15 +641,15 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
*(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \
}
-#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX) \
+#define FFI_INIT_TRAMPOLINE_WIN32(TRAMP,FUN,CTX) \
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
unsigned int __fun = (unsigned int)(FUN); \
unsigned int __ctx = (unsigned int)(CTX); \
unsigned int __dis = __fun - (__ctx + 10); \
- *(unsigned char*) &__tramp[0] = 0xb8; \
- *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
- *(unsigned char *) &__tramp[5] = 0xe8; \
- *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \
+ *(unsigned char*) &__tramp[0] = 0x68; \
+ *(unsigned int*) &__tramp[1] = __ctx; /* push __ctx */ \
+ *(unsigned char*) &__tramp[5] = 0xe9; \
+ *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
}
/* the cif must already be prep'ed */
@@ -656,21 +679,27 @@ ffi_prep_closure_loc (ffi_closure* closure,
&ffi_closure_SYSV,
(void*)codeloc);
}
+ else if (cif->abi == FFI_REGISTER)
+ {
+ FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
+ &ffi_closure_REGISTER,
+ (void*)codeloc);
+ }
else if (cif->abi == FFI_FASTCALL)
{
- FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
+ FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
&ffi_closure_FASTCALL,
(void*)codeloc);
}
else if (cif->abi == FFI_THISCALL)
{
- FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
+ FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
&ffi_closure_THISCALL,
(void*)codeloc);
}
- else if (cif->abi == FFI_STDCALL)
+ else if (cif->abi == FFI_STDCALL || cif->abi == FFI_PASCAL)
{
- FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
+ FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
&ffi_closure_STDCALL,
(void*)codeloc);
}
diff --git a/src/x86/win32.S b/src/x86/win32.S
index 1104ead..96e27df 100644
--- a/src/x86/win32.S
+++ b/src/x86/win32.S
@@ -34,8 +34,8 @@
#include <fficonfig.h>
#include <ffi.h>
-#define CIF_ABI_OFFSET 0
#define CIF_BYTES_OFFSET 16
+#define CIF_FLAGS_OFFSET 20
#ifdef _MSC_VER
@@ -45,6 +45,7 @@
.MODEL FLAT, C
EXTRN ffi_closure_SYSV_inner:NEAR
+EXTRN ffi_closure_WIN32_inner:NEAR
_TEXT SEGMENT
@@ -215,7 +216,7 @@ ffi_closure_THISCALL PROC NEAR
ffi_closure_THISCALL ENDP
ffi_closure_FASTCALL PROC NEAR
- ;; Insert the register argument on the stack as the first argument
+ ;; Insert the 2 register arguments on the stack as the first argument
xchg DWORD PTR [esp+4], edx
xchg DWORD PTR [esp], ecx
push edx
@@ -223,6 +224,16 @@ ffi_closure_FASTCALL PROC NEAR
jmp ffi_closure_STDCALL
ffi_closure_FASTCALL ENDP
+ffi_closure_REGISTER PROC NEAR
+ ;; Insert the 3 register arguments on the stack as the first argument
+ push eax
+ xchg DWORD PTR [esp+8], ecx
+ xchg DWORD PTR [esp+4], edx
+ push ecx
+ push edx
+ jmp ffi_closure_STDCALL
+ffi_closure_FASTCALL ENDP
+
ffi_closure_SYSV PROC NEAR FORCEFRAME
;; the ffi_closure ctx is passed in eax by the trampoline.
@@ -320,7 +331,6 @@ ffi_closure_SYSV ENDP
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
-#define CIF_FLAGS_OFFSET 20
ffi_closure_raw_THISCALL PROC NEAR USES esi FORCEFRAME
sub esp, 36
@@ -417,7 +427,7 @@ ffi_closure_raw_SYSV ENDP
#endif /* !FFI_NO_RAW_API */
ffi_closure_STDCALL PROC NEAR FORCEFRAME
- ;; the ffi_closure ctx is passed in eax by the trampoline.
+ mov eax, [esp] ;; the ffi_closure ctx passed by the trampoline.
sub esp, 40
lea edx, [ebp - 24]
@@ -427,9 +437,13 @@ ffi_closure_STDCALL PROC NEAR FORCEFRAME
lea edx, [ebp - 12]
mov [esp + 4], edx ;; &resp
mov [esp], eax ;; closure
- call ffi_closure_SYSV_inner
+ call ffi_closure_WIN32_inner
mov ecx, [ebp - 12]
+ xchg [ebp + 4], eax ;;xchg size of stack parameters and ffi_closure ctx
+ mov eax, DWORD PTR [eax + CLOSURE_CIF_OFFSET]
+ mov eax, DWORD PTR [eax + CIF_FLAGS_OFFSET]
+
cd_jumptable:
jmp [cd_jumpdata + 4 * eax]
cd_jumpdata:
@@ -493,21 +507,10 @@ cd_retlongdouble:
cd_epilogue:
mov esp, ebp
pop ebp
- pop ecx
- pop edx
- mov ecx, DWORD PTR [ecx + (CLOSURE_CIF_OFFSET-10)]
- add esp, DWORD PTR [ecx + CIF_BYTES_OFFSET]
- mov ecx, DWORD PTR [ecx + CIF_ABI_OFFSET]
- cmp ecx, 3
- je cd_thiscall
- cmp ecx, 4
- jne cd_not_fastcall
-
- add esp, 4
-cd_thiscall:
- add esp, 4
-cd_not_fastcall:
- jmp edx
+ mov ecx, [esp + 4] ;; Return address
+ add esp, [esp] ;; Parameters stack size
+ add esp, 8
+ jmp ecx
ffi_closure_STDCALL ENDP
_TEXT ENDS
@@ -728,14 +731,27 @@ FFI_HIDDEN(ffi_closure_FASTCALL)
.def _ffi_closure_FASTCALL; .scl 2; .type 32; .endef
#endif
USCORE_SYMBOL(ffi_closure_FASTCALL):
- /* Insert the register arguments on the stack as the first two arguments */
+ /* Insert the 2 register arguments on the stack as the first two arguments */
xchg %edx, 4(%esp)
xchg %ecx, (%esp)
push %edx
push %ecx
jmp .ffi_closure_STDCALL_internal
+FFI_HIDDEN(ffi_closure_REGISTER)
+ .globl USCORE_SYMBOL(ffi_closure_REGISTER)
+#if defined(X86_WIN32) && !defined(__OS2__)
+ .def _ffi_closure_REGISTER; .scl 2; .type 32; .endef
+#endif
+USCORE_SYMBOL(ffi_closure_REGISTER):
+ /* Insert the 3 register arguments on the stack as the first two arguments */
+ push %eax
+ xchg %ecx, 8(%esp)
+ xchg %edx, 4(%esp)
+ push %ecx
+ push %edx
+ jmp .ffi_closure_STDCALL_internal
+
.LFE1:
-
# This assumes we are using gas.
.balign 16
FFI_HIDDEN(ffi_closure_SYSV)
@@ -879,7 +895,6 @@ USCORE_SYMBOL(ffi_closure_SYSV):
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
-#define CIF_FLAGS_OFFSET 20
#ifdef X86_WIN32
.balign 16
@@ -1032,6 +1047,8 @@ FFI_HIDDEN(ffi_closure_STDCALL)
#endif
USCORE_SYMBOL(ffi_closure_STDCALL):
.ffi_closure_STDCALL_internal:
+ /* ffi_closure ctx is at top of the stack */
+ movl (%esp), %eax
.LFB5:
pushl %ebp
.LCFI9:
@@ -1045,19 +1062,23 @@ USCORE_SYMBOL(ffi_closure_STDCALL):
leal -12(%ebp), %edx
movl %edx, (%esp) /* &resp */
#if defined(HAVE_HIDDEN_VISIBILITY_ATTRIBUTE) || !defined(__PIC__)
- call USCORE_SYMBOL(ffi_closure_SYSV_inner)
+ call USCORE_SYMBOL(ffi_closure_WIN32_inner)
#elif defined(X86_DARWIN)
- calll L_ffi_closure_SYSV_inner$stub
+ calll L_ffi_closure_WIN32_inner$stub
#else
movl %ebx, 8(%esp)
call 1f
-1: popl %ebx
+1: popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
- call ffi_closure_SYSV_inner@PLT
+ call ffi_closure_WIN32_inner@PLT
movl 8(%esp), %ebx
#endif
movl -12(%ebp), %ecx
0:
+ xchgl 4(%ebp), %eax /* xchg size of stack parameters and ffi_closure ctx */
+ movl CLOSURE_CIF_OFFSET(%eax), %eax
+ movl CIF_FLAGS_OFFSET(%eax), %eax
+
call 1f
# Do not insert anything here between the call and the jump table.
.Lscls_store_table:
@@ -1144,19 +1165,10 @@ USCORE_SYMBOL(ffi_closure_STDCALL):
.Lscls_epilogue:
movl %ebp, %esp
popl %ebp
- popl %ecx
- popl %edx
- movl (CLOSURE_CIF_OFFSET-10)(%ecx), %ecx
- addl CIF_BYTES_OFFSET(%ecx), %esp
- movl CIF_ABI_OFFSET(%ecx), %ecx
- cmpl $3, %ecx /* FFI_THISCALL */
- je 1f
- cmpl $4, %ecx /* FFI_FASTCALL */
- jne 2f
-
- addl $4, %esp
-1: addl $4, %esp
-2: jmp *%edx
+ movl 4(%esp), %ecx /* Return address */
+ addl (%esp), %esp /* Parameters stack size */
+ addl $8, %esp
+ jmp *%ecx
.ffi_closure_STDCALL_end:
.LFE5:
@@ -1165,6 +1177,9 @@ USCORE_SYMBOL(ffi_closure_STDCALL):
L_ffi_closure_SYSV_inner$stub:
.indirect_symbol _ffi_closure_SYSV_inner
hlt ; hlt ; hlt ; hlt ; hlt
+L_ffi_closure_WIN32_inner$stub:
+ .indirect_symbol _ffi_closure_WIN32_inner
+ hlt ; hlt ; hlt ; hlt ; hlt
#endif
#if defined(X86_WIN32) && !defined(__OS2__)