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