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