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_uint64$ 213 214 mov rax, QWORD PTR RVALUE[rbp] 215 movlpd QWORD PTR [rax], xmm0 216 jmp SHORT ret_void$ 217 218ret_uint64$: 219 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT64 220 jne SHORT ret_sint64$ 221 222 mov rcx, QWORD PTR RVALUE[rbp] 223 mov QWORD PTR [rcx], rax 224 jmp SHORT ret_void$ 225 226ret_sint64$: 227 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64 228 jne SHORT ret_pointer$ 229 230 mov rcx, QWORD PTR RVALUE[rbp] 231 mov QWORD PTR [rcx], rax 232 jmp SHORT ret_void$ 233 234ret_pointer$: 235 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_POINTER 236 jne SHORT ret_int$ 237 238 mov rcx, QWORD PTR RVALUE[rbp] 239 mov QWORD PTR [rcx], rax 240 jmp SHORT ret_void$ 241 242ret_int$: 243 cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_INT 244 jne SHORT ret_void$ 245 246 mov rcx, QWORD PTR RVALUE[rbp] 247 cdqe 248 mov QWORD PTR [rcx], rax 249 jmp SHORT ret_void$ 250 251ret_void$: 252 xor rax, rax 253 254 lea rsp, QWORD PTR [rbp+16] 255 pop rbp 256 ret 0 257ffi_call_win64 ENDP 258_TEXT ENDS 259END 260 261#else 262 263#ifdef SYMBOL_UNDERSCORE 264#define SYMBOL_NAME(name) _##name 265#else 266#define SYMBOL_NAME(name) name 267#endif 268 269.text 270 271.extern SYMBOL_NAME(ffi_closure_win64_inner) 272 273# ffi_closure_win64 will be called with these registers set: 274# rax points to 'closure' 275# r11 contains a bit mask that specifies which of the 276# first four parameters are float or double 277# 278# It must move the parameters passed in registers to their stack location, 279# call ffi_closure_win64_inner for the actual work, then return the result. 280# 281 .balign 16 282 .globl SYMBOL_NAME(ffi_closure_win64) 283 .seh_proc SYMBOL_NAME(ffi_closure_win64) 284SYMBOL_NAME(ffi_closure_win64): 285 # copy register arguments onto stack 286 test $1,%r11 287 jne .Lfirst_is_float 288 mov %rcx, 8(%rsp) 289 jmp .Lsecond 290.Lfirst_is_float: 291 movlpd %xmm0, 8(%rsp) 292 293.Lsecond: 294 test $2, %r11 295 jne .Lsecond_is_float 296 mov %rdx, 16(%rsp) 297 jmp .Lthird 298.Lsecond_is_float: 299 movlpd %xmm1, 16(%rsp) 300 301.Lthird: 302 test $4, %r11 303 jne .Lthird_is_float 304 mov %r8,24(%rsp) 305 jmp .Lfourth 306.Lthird_is_float: 307 movlpd %xmm2, 24(%rsp) 308 309.Lfourth: 310 test $8, %r11 311 jne .Lfourth_is_float 312 mov %r9, 32(%rsp) 313 jmp .Ldone 314.Lfourth_is_float: 315 movlpd %xmm3, 32(%rsp) 316 317.Ldone: 318 .seh_stackalloc 40 319 sub $40, %rsp 320 .seh_endprologue 321 mov %rax, %rcx # context is first parameter 322 mov %rsp, %rdx # stack is second parameter 323 add $48, %rdx # point to start of arguments 324 leaq SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax 325 callq *%rax # call the real closure function 326 add $40, %rsp 327 movq %rax, %xmm0 # If the closure returned a float, 328 # ffi_closure_win64_inner wrote it to rax 329 retq 330 .seh_endproc 331 332 .balign 16 333 .globl SYMBOL_NAME(ffi_call_win64) 334 .seh_proc SYMBOL_NAME(ffi_call_win64) 335SYMBOL_NAME(ffi_call_win64): 336 # copy registers onto stack 337 mov %r9,32(%rsp) 338 mov %r8,24(%rsp) 339 mov %rdx,16(%rsp) 340 mov %rcx,8(%rsp) 341 .seh_pushreg rbp 342 push %rbp 343 .seh_stackalloc 48 344 sub $48,%rsp 345 .seh_setframe rbp, 32 346 lea 32(%rsp),%rbp 347 .seh_endprologue 348 349 mov CIF_BYTES(%rbp),%eax 350 add $15, %rax 351 and $-16, %rax 352 cmpq $0x1000, %rax 353 jb Lch_done 354Lch_probe: 355 subq $0x1000,%rsp 356 orl $0x0, (%rsp) 357 subq $0x1000,%rax 358 cmpq $0x1000,%rax 359 ja Lch_probe 360Lch_done: 361 subq %rax, %rsp 362 orl $0x0, (%rsp) 363 lea 32(%rsp), %rax 364 mov %rax, STACK(%rbp) 365 366 mov ECIF(%rbp), %rdx 367 mov STACK(%rbp), %rcx 368 callq *PREP_ARGS_FN(%rbp) 369 370 mov STACK(%rbp), %rsp 371 372 movlpd 24(%rsp), %xmm3 373 movd %xmm3, %r9 374 375 movlpd 16(%rsp), %xmm2 376 movd %xmm2, %r8 377 378 movlpd 8(%rsp), %xmm1 379 movd %xmm1, %rdx 380 381 movlpd (%rsp), %xmm0 382 movd %xmm0, %rcx 383 384 callq *FN(%rbp) 385.Lret_struct4b: 386 cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp) 387 jne .Lret_struct2b 388 389 mov RVALUE(%rbp), %rcx 390 mov %eax, (%rcx) 391 jmp .Lret_void 392 393.Lret_struct2b: 394 cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp) 395 jne .Lret_struct1b 396 397 mov RVALUE(%rbp), %rcx 398 mov %ax, (%rcx) 399 jmp .Lret_void 400 401.Lret_struct1b: 402 cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp) 403 jne .Lret_uint8 404 405 mov RVALUE(%rbp), %rcx 406 mov %al, (%rcx) 407 jmp .Lret_void 408 409.Lret_uint8: 410 cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp) 411 jne .Lret_sint8 412 413 mov RVALUE(%rbp), %rcx 414 movzbq %al, %rax 415 movq %rax, (%rcx) 416 jmp .Lret_void 417 418.Lret_sint8: 419 cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp) 420 jne .Lret_uint16 421 422 mov RVALUE(%rbp), %rcx 423 movsbq %al, %rax 424 movq %rax, (%rcx) 425 jmp .Lret_void 426 427.Lret_uint16: 428 cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp) 429 jne .Lret_sint16 430 431 mov RVALUE(%rbp), %rcx 432 movzwq %ax, %rax 433 movq %rax, (%rcx) 434 jmp .Lret_void 435 436.Lret_sint16: 437 cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp) 438 jne .Lret_uint32 439 440 mov RVALUE(%rbp), %rcx 441 movswq %ax, %rax 442 movq %rax, (%rcx) 443 jmp .Lret_void 444 445.Lret_uint32: 446 cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp) 447 jne .Lret_sint32 448 449 mov RVALUE(%rbp), %rcx 450 movl %eax, %eax 451 movq %rax, (%rcx) 452 jmp .Lret_void 453 454.Lret_sint32: 455 cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp) 456 jne .Lret_float 457 458 mov RVALUE(%rbp), %rcx 459 cltq 460 movq %rax, (%rcx) 461 jmp .Lret_void 462 463.Lret_float: 464 cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp) 465 jne .Lret_double 466 467 mov RVALUE(%rbp), %rax 468 movss %xmm0, (%rax) 469 jmp .Lret_void 470 471.Lret_double: 472 cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp) 473 jne .Lret_uint64 474 475 mov RVALUE(%rbp), %rax 476 movlpd %xmm0, (%rax) 477 jmp .Lret_void 478 479.Lret_uint64: 480 cmpl $FFI_TYPE_UINT64, CIF_FLAGS(%rbp) 481 jne .Lret_sint64 482 483 mov RVALUE(%rbp), %rcx 484 mov %rax, (%rcx) 485 jmp .Lret_void 486 487.Lret_sint64: 488 cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp) 489 jne .Lret_pointer 490 491 mov RVALUE(%rbp), %rcx 492 mov %rax, (%rcx) 493 jmp .Lret_void 494 495.Lret_pointer: 496 cmpl $FFI_TYPE_POINTER, CIF_FLAGS(%rbp) 497 jne .Lret_int 498 499 mov RVALUE(%rbp), %rcx 500 mov %rax, (%rcx) 501 jmp .Lret_void 502 503.Lret_int: 504 cmpl $FFI_TYPE_INT, CIF_FLAGS(%rbp) 505 jne .Lret_void 506 507 mov RVALUE(%rbp), %rcx 508 cltq 509 movq %rax, (%rcx) 510 jmp .Lret_void 511 512.Lret_void: 513 xor %rax, %rax 514 515 lea 16(%rbp), %rsp 516 pop %rbp 517 retq 518 .seh_endproc 519#endif /* !_MSC_VER */ 520 521