Home | History | Annotate | Download | only in libffi_msvc
      1 /* -----------------------------------------------------------------------
      2    win32.S - Copyright (c) 1996, 1998, 2001, 2002  Red Hat, Inc.
      3 	     Copyright (c) 2001  John Beniton
      4 	     Copyright (c) 2002  Ranjit Mathew
      5 
      6 
      7    X86 Foreign Function Interface
      8 
      9    Permission is hereby granted, free of charge, to any person obtaining
     10    a copy of this software and associated documentation files (the
     11    ``Software''), to deal in the Software without restriction, including
     12    without limitation the rights to use, copy, modify, merge, publish,
     13    distribute, sublicense, and/or sell copies of the Software, and to
     14    permit persons to whom the Software is furnished to do so, subject to
     15    the following conditions:
     16 
     17    The above copyright notice and this permission notice shall be included
     18    in all copies or substantial portions of the Software.
     19 
     20    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
     21    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     23    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     24    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     25    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     26    OTHER DEALINGS IN THE SOFTWARE.
     27    ----------------------------------------------------------------------- */
     28 
     29 /* theller: almost verbatim translation from gas syntax to MSVC inline
     30    assembler code. */
     31 
     32 /* theller: ffi_call_x86 now returns an integer - the difference of the stack
     33    pointer before and after the function call.  If everything is ok, zero is
     34    returned.  If stdcall functions are passed the wrong number of arguments,
     35    the difference will be nonzero. */
     36 
     37 #include <ffi.h>
     38 #include <ffi_common.h>
     39 
     40 __declspec(naked) int
     41 ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */
     42 	     extended_cif *ecif, /* 12 */
     43 	     unsigned bytes, /* 16 */
     44 	     unsigned flags, /* 20 */
     45 	     unsigned *rvalue, /* 24 */
     46 	     void (*fn)()) /* 28 */
     47 {
     48 	_asm {
     49 		push ebp
     50 		mov ebp, esp
     51 
     52 		push esi // NEW: this register must be preserved across function calls
     53 // XXX SAVE ESP NOW!
     54 		mov esi, esp		// save stack pointer before the call
     55 
     56 // Make room for all of the new args.
     57 		mov ecx, [ebp+16]
     58 		sub esp, ecx		// sub esp, bytes
     59 
     60 		mov eax, esp
     61 
     62 // Place all of the ffi_prep_args in position
     63 		push [ebp + 12] // ecif
     64 		push eax
     65 		call [ebp + 8] // prepfunc
     66 
     67 // Return stack to previous state and call the function
     68 		add esp, 8
     69 // FIXME: Align the stack to a 128-bit boundary to avoid
     70 // potential performance hits.
     71 		call [ebp + 28]
     72 
     73 // Load ecif->cif->abi
     74 		mov ecx, [ebp + 12]
     75 		mov ecx, [ecx]ecif.cif
     76 		mov ecx, [ecx]ecif.cif.abi
     77 
     78 		cmp ecx, FFI_STDCALL
     79 		je noclean
     80 // STDCALL: Remove the space we pushed for the args
     81 		mov ecx, [ebp + 16]
     82 		add esp, ecx
     83 // CDECL: Caller has already cleaned the stack
     84 noclean:
     85 // Check that esp has the same value as before!
     86 		sub esi, esp
     87 
     88 // Load %ecx with the return type code
     89 		mov ecx, [ebp + 20]
     90 
     91 // If the return value pointer is NULL, assume no return value.
     92 /*
     93   Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
     94   otherwise only one BYTE will be compared (instead of a DWORD)!
     95  */
     96 		cmp DWORD PTR [ebp + 24], 0
     97 		jne sc_retint
     98 
     99 // Even if there is no space for the return value, we are
    100 // obliged to handle floating-point values.
    101 		cmp ecx, FFI_TYPE_FLOAT
    102 		jne sc_noretval
    103 //        fstp  %st(0)
    104 		fstp st(0)
    105 
    106 		jmp sc_epilogue
    107 
    108 sc_retint:
    109 		cmp ecx, FFI_TYPE_INT
    110 		jne sc_retfloat
    111 //        # Load %ecx with the pointer to storage for the return value
    112 		mov ecx, [ebp + 24]
    113 		mov [ecx + 0], eax
    114 		jmp sc_epilogue
    115 
    116 sc_retfloat:
    117 		cmp ecx, FFI_TYPE_FLOAT
    118 		jne sc_retdouble
    119 // Load %ecx with the pointer to storage for the return value
    120 		mov ecx, [ebp+24]
    121 //        fstps (%ecx)
    122 		fstp DWORD PTR [ecx]
    123 		jmp sc_epilogue
    124 
    125 sc_retdouble:
    126 		cmp ecx, FFI_TYPE_DOUBLE
    127 		jne sc_retlongdouble
    128 //        movl  24(%ebp),%ecx
    129 		mov ecx, [ebp+24]
    130 		fstp QWORD PTR [ecx]
    131 		jmp sc_epilogue
    132 
    133 		jmp sc_retlongdouble // avoid warning about unused label
    134 sc_retlongdouble:
    135 		cmp ecx, FFI_TYPE_LONGDOUBLE
    136 		jne sc_retint64
    137 // Load %ecx with the pointer to storage for the return value
    138 		mov ecx, [ebp+24]
    139 //        fstpt (%ecx)
    140 		fstp QWORD PTR [ecx] /* XXX ??? */
    141 		jmp sc_epilogue
    142 
    143 sc_retint64:
    144 		cmp ecx, FFI_TYPE_SINT64
    145 		jne sc_retstruct
    146 // Load %ecx with the pointer to storage for the return value
    147 		mov ecx, [ebp+24]
    148 		mov [ecx+0], eax
    149 		mov [ecx+4], edx
    150 
    151 sc_retstruct:
    152 // Nothing to do!
    153 
    154 sc_noretval:
    155 sc_epilogue:
    156 		mov eax, esi
    157 		pop esi // NEW restore: must be preserved across function calls
    158 		mov esp, ebp
    159 		pop ebp
    160 		ret
    161 	}
    162 }
    163