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