1#define LIBFFI_ASM 2#include <fficonfig.h> 3#include <ffi.h> 4 5/* Constants for ffi_call_win64 */ 6#define STACK 0 7#define PREP_ARGS_FN 32 8#define ECIF 40 9#define CIF_BYTES 48 10#define CIF_FLAGS 56 11#define RVALUE 64 12#define FN 72 13 14/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *), 15 extended_cif *ecif, unsigned bytes, unsigned flags, 16 unsigned *rvalue, void (*fn)()); 17 */ 18 19#ifdef _MSC_VER 20PUBLIC ffi_call_win64 21 22EXTRN __chkstk:NEAR 23EXTRN ffi_closure_win64_inner:NEAR 24 25_TEXT SEGMENT 26 27;;; ffi_closure_win64 will be called with these registers set: 28;;; rax points to 'closure' 29;;; r11 contains a bit mask that specifies which of the 30;;; first four parameters are float or double 31;;; 32;;; It must move the parameters passed in registers to their stack location, 33;;; call ffi_closure_win64_inner for the actual work, then return the result. 34;;; 35ffi_closure_win64 PROC FRAME 36 ;; copy register arguments onto stack 37 test r11, 1 38 jne first_is_float 39 mov QWORD PTR [rsp+8], rcx 40 jmp second 41first_is_float: 42 movlpd QWORD PTR [rsp+8], xmm0 43 44second: 45 test r11, 2 46 jne second_is_float 47 mov QWORD PTR [rsp+16], rdx 48 jmp third 49second_is_float: 50 movlpd QWORD PTR [rsp+16], xmm1 51 52third: 53 test r11, 4 54 jne third_is_float 55 mov QWORD PTR [rsp+24], r8 56 jmp fourth 57third_is_float: 58 movlpd QWORD PTR [rsp+24], xmm2 59 60fourth: 61 test r11, 8 62 jne fourth_is_float 63 mov QWORD PTR [rsp+32], r9 64 jmp done 65fourth_is_float: 66 movlpd QWORD PTR [rsp+32], xmm3 67 68done: 69 .ALLOCSTACK 40 70 sub rsp, 40 71 .ENDPROLOG 72 mov rcx, rax ; context is first parameter 73 mov rdx, rsp ; stack is second parameter 74 add rdx, 48 ; point to start of arguments 75 mov rax, ffi_closure_win64_inner 76 call rax ; call the real closure function 77 add rsp, 40 78 movd xmm0, rax ; If the closure returned a float, 79 ; ffi_closure_win64_inner wrote it to rax 80 ret 0 81ffi_closure_win64 ENDP 82 83ffi_call_win64 PROC FRAME 84 ;; copy registers onto stack 85 mov QWORD PTR [rsp+32], r9 86 mov QWORD PTR [rsp+24], r8 87 mov QWORD PTR [rsp+16], rdx 88 mov QWORD PTR [rsp+8], rcx 89 .PUSHREG rbp 90 push rbp 91 .ALLOCSTACK 48 92 sub rsp, 48 ; 00000030H 93 .SETFRAME rbp, 32 94 lea rbp, QWORD PTR [rsp+32] 95 .ENDPROLOG 96 97 mov eax, DWORD PTR CIF_BYTES[rbp] 98 add rax, 15 99 and rax, -16 100 call __chkstk 101 sub rsp, rax 102 lea rax, QWORD PTR [rsp+32] 103 mov QWORD PTR STACK[rbp], rax 104 105 mov rdx, QWORD PTR ECIF[rbp] 106 mov rcx, QWORD PTR STACK[rbp] 107 call QWORD PTR PREP_ARGS_FN[rbp] 108 109 mov rsp, QWORD PTR STACK[rbp] 110 111 movlpd xmm3, QWORD PTR [rsp+24] 112 movd r9, xmm3 113 114 movlpd xmm2, QWORD PTR [rsp+16] 115 movd r8, xmm2 116 117 movlpd xmm1, QWORD PTR [rsp+8] 118 movd rdx, xmm1 119 120 movlpd xmm0, QWORD PTR [rsp] 121 movd rcx, xmm0 122 123 call QWORD PTR FN[rbp] 124ret_struct4b$: 125 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B 126 jne ret_struct2b$ 127 128 mov rcx, QWORD PTR RVALUE[rbp] 129 mov DWORD PTR [rcx], eax 130 jmp ret_void$ 131 132ret_struct2b$: 133 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B 134 jne ret_struct1b$ 135 136 mov rcx, QWORD PTR RVALUE[rbp] 137 mov WORD PTR [rcx], ax 138 jmp ret_void$ 139 140ret_struct1b$: 141 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B 142 jne ret_uint8$ 143 144 mov rcx, QWORD PTR RVALUE[rbp] 145 mov BYTE PTR [rcx], al 146 jmp ret_void$ 147 148ret_uint8$: 149 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8 150 jne ret_sint8$ 151 152 mov rcx, QWORD PTR RVALUE[rbp] 153 movzx rax, al 154 mov QWORD PTR [rcx], rax 155 jmp ret_void$ 156 157ret_sint8$: 158 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8 159 jne ret_uint16$ 160 161 mov rcx, QWORD PTR RVALUE[rbp] 162 movsx rax, al 163 mov QWORD PTR [rcx], rax 164 jmp ret_void$ 165 166ret_uint16$: 167 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16 168 jne ret_sint16$ 169 170 mov rcx, QWORD PTR RVALUE[rbp] 171 movzx rax, ax 172 mov QWORD PTR [rcx], rax 173 jmp SHORT ret_void$ 174 175ret_sint16$: 176 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16 177 jne ret_uint32$ 178 179 mov rcx, QWORD PTR RVALUE[rbp] 180 movsx rax, ax 181 mov QWORD PTR [rcx], rax 182 jmp SHORT ret_void$ 183 184ret_uint32$: 185 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32 186 jne ret_sint32$ 187 188 mov rcx, QWORD PTR RVALUE[rbp] 189 mov eax, eax 190 mov QWORD PTR [rcx], rax 191 jmp SHORT ret_void$ 192 193ret_sint32$: 194 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32 195 jne ret_float$ 196 197 mov rcx, QWORD PTR RVALUE[rbp] 198 cdqe 199 mov QWORD PTR [rcx], rax 200 jmp SHORT ret_void$ 201 202ret_float$: 203 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT 204 jne SHORT ret_double$ 205 206 mov rax, QWORD PTR RVALUE[rbp] 207 movss DWORD PTR [rax], xmm0 208 jmp SHORT ret_void$ 209 210ret_double$: 211 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE 212 jne SHORT ret_sint64$ 213 214 mov rax, QWORD PTR RVALUE[rbp] 215 movlpd QWORD PTR [rax], xmm0 216 jmp SHORT ret_void$ 217 218ret_sint64$: 219 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64 220 jne ret_void$ 221 222 mov rcx, QWORD PTR RVALUE[rbp] 223 mov QWORD PTR [rcx], rax 224 jmp SHORT ret_void$ 225 226ret_void$: 227 xor rax, rax 228 229 lea rsp, QWORD PTR [rbp+16] 230 pop rbp 231 ret 0 232ffi_call_win64 ENDP 233_TEXT ENDS 234END 235 236#else 237 238#ifdef SYMBOL_UNDERSCORE 239#define SYMBOL_NAME(name) _##name 240#else 241#define SYMBOL_NAME(name) name 242#endif 243 244.text 245 246.extern SYMBOL_NAME(ffi_closure_win64_inner) 247 248# ffi_closure_win64 will be called with these registers set: 249# rax points to 'closure' 250# r11 contains a bit mask that specifies which of the 251# first four parameters are float or double 252# 253# It must move the parameters passed in registers to their stack location, 254# call ffi_closure_win64_inner for the actual work, then return the result. 255# 256 .balign 16 257 .globl SYMBOL_NAME(ffi_closure_win64) 258SYMBOL_NAME(ffi_closure_win64): 259 # copy register arguments onto stack 260 test $1,%r11 261 jne .Lfirst_is_float 262 mov %rcx, 8(%rsp) 263 jmp .Lsecond 264.Lfirst_is_float: 265 movlpd %xmm0, 8(%rsp) 266 267.Lsecond: 268 test $2, %r11 269 jne .Lsecond_is_float 270 mov %rdx, 16(%rsp) 271 jmp .Lthird 272.Lsecond_is_float: 273 movlpd %xmm1, 16(%rsp) 274 275.Lthird: 276 test $4, %r11 277 jne .Lthird_is_float 278 mov %r8,24(%rsp) 279 jmp .Lfourth 280.Lthird_is_float: 281 movlpd %xmm2, 24(%rsp) 282 283.Lfourth: 284 test $8, %r11 285 jne .Lfourth_is_float 286 mov %r9, 32(%rsp) 287 jmp .Ldone 288.Lfourth_is_float: 289 movlpd %xmm3, 32(%rsp) 290 291.Ldone: 292#.ALLOCSTACK 40 293 sub $40, %rsp 294#.ENDPROLOG 295 mov %rax, %rcx # context is first parameter 296 mov %rsp, %rdx # stack is second parameter 297 add $48, %rdx # point to start of arguments 298 mov $SYMBOL_NAME(ffi_closure_win64_inner), %rax 299 callq *%rax # call the real closure function 300 add $40, %rsp 301 movq %rax, %xmm0 # If the closure returned a float, 302 # ffi_closure_win64_inner wrote it to rax 303 retq 304.ffi_closure_win64_end: 305 306 .balign 16 307 .globl SYMBOL_NAME(ffi_call_win64) 308SYMBOL_NAME(ffi_call_win64): 309 # copy registers onto stack 310 mov %r9,32(%rsp) 311 mov %r8,24(%rsp) 312 mov %rdx,16(%rsp) 313 mov %rcx,8(%rsp) 314 #.PUSHREG rbp 315 push %rbp 316 #.ALLOCSTACK 48 317 sub $48,%rsp 318 #.SETFRAME rbp, 32 319 lea 32(%rsp),%rbp 320 #.ENDPROLOG 321 322 mov CIF_BYTES(%rbp),%eax 323 add $15, %rax 324 and $-16, %rax 325 cmpq $0x1000, %rax 326 jb Lch_done 327Lch_probe: 328 subq $0x1000,%rsp 329 orl $0x0, (%rsp) 330 subq $0x1000,%rax 331 cmpq $0x1000,%rax 332 ja Lch_probe 333Lch_done: 334 subq %rax, %rsp 335 orl $0x0, (%rsp) 336 lea 32(%rsp), %rax 337 mov %rax, STACK(%rbp) 338 339 mov ECIF(%rbp), %rdx 340 mov STACK(%rbp), %rcx 341 callq *PREP_ARGS_FN(%rbp) 342 343 mov STACK(%rbp), %rsp 344 345 movlpd 24(%rsp), %xmm3 346 movd %xmm3, %r9 347 348 movlpd 16(%rsp), %xmm2 349 movd %xmm2, %r8 350 351 movlpd 8(%rsp), %xmm1 352 movd %xmm1, %rdx 353 354 movlpd (%rsp), %xmm0 355 movd %xmm0, %rcx 356 357 callq *FN(%rbp) 358.Lret_struct4b: 359 cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp) 360 jne .Lret_struct2b 361 362 mov RVALUE(%rbp), %rcx 363 mov %eax, (%rcx) 364 jmp .Lret_void 365 366.Lret_struct2b: 367 cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp) 368 jne .Lret_struct1b 369 370 mov RVALUE(%rbp), %rcx 371 mov %ax, (%rcx) 372 jmp .Lret_void 373 374.Lret_struct1b: 375 cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp) 376 jne .Lret_uint8 377 378 mov RVALUE(%rbp), %rcx 379 mov %al, (%rcx) 380 jmp .Lret_void 381 382.Lret_uint8: 383 cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp) 384 jne .Lret_sint8 385 386 mov RVALUE(%rbp), %rcx 387 movzbq %al, %rax 388 movq %rax, (%rcx) 389 jmp .Lret_void 390 391.Lret_sint8: 392 cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp) 393 jne .Lret_uint16 394 395 mov RVALUE(%rbp), %rcx 396 movsbq %al, %rax 397 movq %rax, (%rcx) 398 jmp .Lret_void 399 400.Lret_uint16: 401 cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp) 402 jne .Lret_sint16 403 404 mov RVALUE(%rbp), %rcx 405 movzwq %ax, %rax 406 movq %rax, (%rcx) 407 jmp .Lret_void 408 409.Lret_sint16: 410 cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp) 411 jne .Lret_uint32 412 413 mov RVALUE(%rbp), %rcx 414 movswq %ax, %rax 415 movq %rax, (%rcx) 416 jmp .Lret_void 417 418.Lret_uint32: 419 cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp) 420 jne .Lret_sint32 421 422 mov RVALUE(%rbp), %rcx 423 movl %eax, %eax 424 movq %rax, (%rcx) 425 jmp .Lret_void 426 427.Lret_sint32: 428 cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp) 429 jne .Lret_float 430 431 mov RVALUE(%rbp), %rcx 432 cltq 433 movq %rax, (%rcx) 434 jmp .Lret_void 435 436.Lret_float: 437 cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp) 438 jne .Lret_double 439 440 mov RVALUE(%rbp), %rax 441 movss %xmm0, (%rax) 442 jmp .Lret_void 443 444.Lret_double: 445 cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp) 446 jne .Lret_sint64 447 448 mov RVALUE(%rbp), %rax 449 movlpd %xmm0, (%rax) 450 jmp .Lret_void 451 452.Lret_sint64: 453 cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp) 454 jne .Lret_void 455 456 mov RVALUE(%rbp), %rcx 457 mov %rax, (%rcx) 458 jmp .Lret_void 459 460.Lret_void: 461 xor %rax, %rax 462 463 lea 16(%rbp), %rsp 464 pop %rbp 465 retq 466.ffi_call_win64_end: 467#endif /* !_MSC_VER */ 468 469