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 20 PUBLIC ffi_call_win64 21 22 EXTRN __chkstk:NEAR 23 EXTRN 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 ;;; 35 ffi_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 41 first_is_float: 42 movlpd QWORD PTR [rsp+8], xmm0 43 44 second: 45 test r11, 2 46 jne second_is_float 47 mov QWORD PTR [rsp+16], rdx 48 jmp third 49 second_is_float: 50 movlpd QWORD PTR [rsp+16], xmm1 51 52 third: 53 test r11, 4 54 jne third_is_float 55 mov QWORD PTR [rsp+24], r8 56 jmp fourth 57 third_is_float: 58 movlpd QWORD PTR [rsp+24], xmm2 59 60 fourth: 61 test r11, 8 62 jne fourth_is_float 63 mov QWORD PTR [rsp+32], r9 64 jmp done 65 fourth_is_float: 66 movlpd QWORD PTR [rsp+32], xmm3 67 68 done: 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 81 ffi_closure_win64 ENDP 82 83 ffi_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] 124 ret_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 132 ret_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 140 ret_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 148 ret_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 157 ret_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 166 ret_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 175 ret_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 184 ret_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 193 ret_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 202 ret_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 210 ret_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 218 ret_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 226 ret_void$: 227 xor rax, rax 228 229 lea rsp, QWORD PTR [rbp+16] 230 pop rbp 231 ret 0 232 ffi_call_win64 ENDP 233 _TEXT ENDS 234 END 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) 258 SYMBOL_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) 308 SYMBOL_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 327 Lch_probe: 328 subq $0x1000,%rsp 329 orl $0x0, (%rsp) 330 subq $0x1000,%rax 331 cmpq $0x1000,%rax 332 ja Lch_probe 333 Lch_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