1#ifdef __i386__
2/* -----------------------------------------------------------------------
3   ffi.c - Copyright (c) 1996, 1998, 1999, 2001  Red Hat, Inc.
4           Copyright (c) 2002  Ranjit Mathew
5           Copyright (c) 2002  Bo Thorsen
6           Copyright (c) 2002  Roger Sayle
7
8   x86 Foreign Function Interface
9
10   Permission is hereby granted, free of charge, to any person obtaining
11   a copy of this software and associated documentation files (the
12   ``Software''), to deal in the Software without restriction, including
13   without limitation the rights to use, copy, modify, merge, publish,
14   distribute, sublicense, and/or sell copies of the Software, and to
15   permit persons to whom the Software is furnished to do so, subject to
16   the following conditions:
17
18   The above copyright notice and this permission notice shall be included
19   in all copies or substantial portions of the Software.
20
21   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
22   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27   OTHER DEALINGS IN THE SOFTWARE.
28   ----------------------------------------------------------------------- */
29
30//#ifndef __x86_64__
31
32#include <ffi.h>
33#include <ffi_common.h>
34
35#include <stdlib.h>
36
37//void ffi_prep_args(char *stack, extended_cif *ecif);
38
39static inline int
40retval_on_stack(
41	ffi_type*	tp)
42{
43	if (tp->type == FFI_TYPE_STRUCT)
44	{
45//		int size = tp->size;
46
47		if (tp->size > 8)
48			return 1;
49
50		switch (tp->size)
51		{
52			case 1: case 2: case 4: case 8:
53				return 0;
54			default:
55				return 1;
56		}
57	}
58
59	return 0;
60}
61
62/* ffi_prep_args is called by the assembly routine once stack space
63   has been allocated for the function's arguments */
64/*@-exportheader@*/
65extern void ffi_prep_args(char*, extended_cif*);
66void
67ffi_prep_args(
68	char*			stack,
69	extended_cif*	ecif)
70/*@=exportheader@*/
71{
72	register unsigned int	i;
73	register void**			p_argv = ecif->avalue;
74	register char*			argp = stack;
75	register ffi_type**		p_arg;
76
77	if (retval_on_stack(ecif->cif->rtype))
78	{
79		*(void**)argp = ecif->rvalue;
80		argp += 4;
81	}
82
83	p_arg = ecif->cif->arg_types;
84
85	for (i = ecif->cif->nargs; i > 0; i--, p_arg++, p_argv++)
86    {
87		size_t z = (*p_arg)->size;
88
89		/* Align if necessary */
90		if ((sizeof(int) - 1) & (unsigned)argp)
91			argp = (char*)ALIGN(argp, sizeof(int));
92
93		if (z < sizeof(int))
94		{
95			z = sizeof(int);
96
97			switch ((*p_arg)->type)
98			{
99				case FFI_TYPE_SINT8:
100					*(signed int*)argp = (signed int)*(SINT8*)(*p_argv);
101					break;
102
103				case FFI_TYPE_UINT8:
104					*(unsigned int*)argp = (unsigned int)*(UINT8*)(*p_argv);
105					break;
106
107				case FFI_TYPE_SINT16:
108					*(signed int*)argp = (signed int)*(SINT16*)(*p_argv);
109					break;
110
111				case FFI_TYPE_UINT16:
112					*(unsigned int*)argp = (unsigned int)*(UINT16*)(*p_argv);
113					break;
114
115				case FFI_TYPE_SINT32:
116					*(signed int*)argp = (signed int)*(SINT32*)(*p_argv);
117					break;
118
119				case FFI_TYPE_UINT32:
120					*(unsigned int*)argp = (unsigned int)*(UINT32*)(*p_argv);
121					break;
122
123				case FFI_TYPE_STRUCT:
124					*(unsigned int*)argp = (unsigned int)*(UINT32*)(*p_argv);
125					break;
126
127				default:
128					FFI_ASSERT(0);
129					break;
130			}
131		}
132		else
133			memcpy(argp, *p_argv, z);
134
135		argp += z;
136	}
137}
138
139/* Perform machine dependent cif processing */
140ffi_status
141ffi_prep_cif_machdep(
142	ffi_cif*	cif)
143{
144	/* Set the return type flag */
145	switch (cif->rtype->type)
146	{
147#if !defined(X86_WIN32)  && !defined(X86_DARWIN)
148		case FFI_TYPE_STRUCT:
149#endif
150		case FFI_TYPE_VOID:
151		case FFI_TYPE_SINT64:
152		case FFI_TYPE_FLOAT:
153		case FFI_TYPE_DOUBLE:
154		case FFI_TYPE_LONGDOUBLE:
155			cif->flags = (unsigned)cif->rtype->type;
156			break;
157
158		case FFI_TYPE_UINT64:
159			cif->flags = FFI_TYPE_SINT64;
160			break;
161
162#if defined(X86_WIN32) || defined(X86_DARWIN)
163		case FFI_TYPE_STRUCT:
164			switch (cif->rtype->size)
165			{
166				case 1:
167					cif->flags = FFI_TYPE_SINT8;
168					break;
169
170				case 2:
171					cif->flags = FFI_TYPE_SINT16;
172					break;
173
174				case 4:
175					cif->flags = FFI_TYPE_INT;
176					break;
177
178				case 8:
179					cif->flags = FFI_TYPE_SINT64;
180					break;
181
182				default:
183					cif->flags = FFI_TYPE_STRUCT;
184					break;
185			}
186
187			break;
188#endif
189
190		default:
191			cif->flags = FFI_TYPE_INT;
192			break;
193	}
194
195	/* Darwin: The stack needs to be aligned to a multiple of 16 bytes */
196	cif->bytes = (cif->bytes + 15) & ~0xF;
197
198	return FFI_OK;
199}
200
201/*@-declundef@*/
202/*@-exportheader@*/
203extern void
204ffi_call_SYSV(
205			void			(*)(char *, extended_cif *),
206/*@out@*/	extended_cif*	,
207			unsigned		,
208			unsigned		,
209/*@out@*/	unsigned*		,
210			void			(*fn)(void));
211/*@=declundef@*/
212/*@=exportheader@*/
213
214#ifdef X86_WIN32
215/*@-declundef@*/
216/*@-exportheader@*/
217extern void
218ffi_call_STDCALL(
219			void			(char *, extended_cif *),
220/*@out@*/	extended_cif*	,
221			unsigned		,
222			unsigned		,
223/*@out@*/	unsigned*		,
224			void			(*fn)(void));
225/*@=declundef@*/
226/*@=exportheader@*/
227#endif /* X86_WIN32 */
228
229void
230ffi_call(
231/*@dependent@*/	ffi_cif*	cif,
232				void		(*fn)(void),
233/*@out@*/		void*		rvalue,
234/*@dependent@*/	void**		avalue)
235{
236	extended_cif ecif;
237
238	ecif.cif = cif;
239	ecif.avalue = avalue;
240
241	/*	If the return value is a struct and we don't have a return
242		value address then we need to make one.	*/
243
244	if ((rvalue == NULL) && retval_on_stack(cif->rtype))
245	{
246		/*@-sysunrecog@*/
247		ecif.rvalue = alloca(cif->rtype->size);
248		/*@=sysunrecog@*/
249	}
250	else
251		ecif.rvalue = rvalue;
252
253	switch (cif->abi)
254	{
255		case FFI_SYSV:
256			/*@-usedef@*/
257			/*	To avoid changing the assembly code make sure the size of the argument
258				block is a multiple of 16. Then add 8 to compensate for local variables
259				in ffi_call_SYSV.	*/
260			ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
261				cif->flags, ecif.rvalue, fn);
262			/*@=usedef@*/
263			break;
264
265#ifdef X86_WIN32
266		case FFI_STDCALL:
267			/*@-usedef@*/
268			ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
269				cif->flags, ecif.rvalue, fn);
270			/*@=usedef@*/
271			break;
272#endif /* X86_WIN32 */
273
274		default:
275			FFI_ASSERT(0);
276			break;
277	}
278}
279
280/** private members **/
281
282static void
283ffi_closure_SYSV(
284	ffi_closure*	closure) __attribute__((regparm(1)));
285
286#if !FFI_NO_RAW_API
287static void
288ffi_closure_raw_SYSV(
289	ffi_raw_closure*	closure) __attribute__((regparm(1)));
290#endif
291
292/*@-exportheader@*/
293static inline
294void
295ffi_prep_incoming_args_SYSV(
296	char*		stack,
297	void**		rvalue,
298	void**		avalue,
299	ffi_cif*	cif)
300/*@=exportheader@*/
301{
302	register unsigned int	i;
303	register void**			p_argv = avalue;
304	register char*			argp = stack;
305	register ffi_type**		p_arg;
306
307	if (retval_on_stack(cif->rtype))
308	{
309		*rvalue = *(void**)argp;
310		argp += 4;
311	}
312
313	for (i = cif->nargs, p_arg = cif->arg_types; i > 0; i--, p_arg++, p_argv++)
314	{
315//		size_t z;
316
317		/* Align if necessary */
318		if ((sizeof(int) - 1) & (unsigned)argp)
319			argp = (char*)ALIGN(argp, sizeof(int));
320
321//		z = (*p_arg)->size;
322
323		/* because we're little endian, this is what it turns into.   */
324		*p_argv = (void*)argp;
325
326		argp += (*p_arg)->size;
327	}
328}
329
330/* This function is jumped to by the trampoline */
331__attribute__((regparm(1)))
332static void
333ffi_closure_SYSV(
334	ffi_closure*	closure)
335{
336	long double	res;
337	ffi_cif*	cif = closure->cif;
338	void**		arg_area = (void**)alloca(cif->nargs * sizeof(void*));
339	void*		resp = (void*)&res;
340	void*		args = __builtin_dwarf_cfa();
341
342	/*	This call will initialize ARG_AREA, such that each
343		element in that array points to the corresponding
344		value on the stack; and if the function returns
345		a structure, it will reset RESP to point to the
346		structure return address.	*/
347	ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
348
349	(closure->fun)(cif, resp, arg_area, closure->user_data);
350
351	/* now, do a generic return based on the value of rtype */
352	if (cif->flags == FFI_TYPE_INT)
353		asm("movl	(%0),%%eax"
354			: : "r" (resp) : "eax");
355	else if (cif->flags == FFI_TYPE_FLOAT)
356		asm("flds	(%0)"
357			: : "r" (resp) : "st");
358	else if (cif->flags == FFI_TYPE_DOUBLE)
359		asm("fldl	(%0)"
360			: : "r" (resp) : "st", "st(1)");
361	else if (cif->flags == FFI_TYPE_LONGDOUBLE)
362 		asm("fldt	(%0)"
363			: : "r" (resp) : "st", "st(1)");
364	else if (cif->flags == FFI_TYPE_SINT64)
365		asm("movl	0(%0),%%eax;"
366			"movl	4(%0),%%edx"
367			: : "r" (resp)
368			: "eax", "edx");
369
370#if defined(X86_WIN32) || defined(X86_DARWIN)
371	else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct  */
372		asm("movsbl	(%0),%%eax"
373			: : "r" (resp) : "eax");
374	else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */
375		asm("movswl	(%0),%%eax"
376			: : "r" (resp) : "eax");
377#endif
378
379	else if (cif->flags == FFI_TYPE_STRUCT)
380		asm("lea -8(%ebp),%esp;"
381			"pop %esi;"
382			"pop %edi;"
383			"pop %ebp;"
384			"ret $4");
385}
386
387
388/* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
389#define FFI_INIT_TRAMPOLINE(TRAMP, FUN, CTX)											\
390	({																					\
391		unsigned char*	__tramp = (unsigned char*)(TRAMP);								\
392		unsigned int	__fun = (unsigned int)(FUN);									\
393		unsigned int	__ctx = (unsigned int)(CTX);									\
394		unsigned int	__dis = __fun - ((unsigned int)__tramp + FFI_TRAMPOLINE_SIZE);	\
395		*(unsigned char*)&__tramp[0] = 0xb8;											\
396		*(unsigned int*)&__tramp[1] = __ctx;	/* movl __ctx, %eax */					\
397		*(unsigned char*)&__tramp[5] = 0xe9;											\
398		*(unsigned int*)&__tramp[6] = __dis;	/* jmp __fun  */						\
399	})
400
401/* the cif must already be prep'ed */
402ffi_status
403ffi_prep_closure(
404	ffi_closure*	closure,
405	ffi_cif*		cif,
406	void			(*fun)(ffi_cif*,void*,void**,void*),
407	void*			user_data)
408{
409//	FFI_ASSERT(cif->abi == FFI_SYSV);
410	if (cif->abi != FFI_SYSV)
411		return FFI_BAD_ABI;
412
413	FFI_INIT_TRAMPOLINE(closure->tramp, &ffi_closure_SYSV, (void*)closure);
414
415	closure->cif		= cif;
416	closure->user_data	= user_data;
417	closure->fun		= fun;
418
419	return FFI_OK;
420}
421
422/* ------- Native raw API support -------------------------------- */
423
424#if !FFI_NO_RAW_API
425
426__attribute__((regparm(1)))
427static void
428ffi_closure_raw_SYSV(
429	ffi_raw_closure*	closure)
430{
431	long double		res;
432	ffi_raw*		raw_args = (ffi_raw*)__builtin_dwarf_cfa();
433	ffi_cif*		cif = closure->cif;
434	unsigned short	rtype = cif->flags;
435	void*			resp = (void*)&res;
436
437	(closure->fun)(cif, resp, raw_args, closure->user_data);
438
439	/* now, do a generic return based on the value of rtype */
440	if (rtype == FFI_TYPE_INT)
441		asm("movl	(%0),%%eax"
442			: : "r" (resp) : "eax");
443	else if (rtype == FFI_TYPE_FLOAT)
444		asm("flds	(%0)"
445			: : "r" (resp) : "st");
446	else if (rtype == FFI_TYPE_DOUBLE)
447		asm("fldl	(%0)"
448			: : "r" (resp) : "st", "st(1)");
449	else if (rtype == FFI_TYPE_LONGDOUBLE)
450		asm("fldt	(%0)"
451			: : "r" (resp) : "st", "st(1)");
452	else if (rtype == FFI_TYPE_SINT64)
453		asm("movl	0(%0),%%eax;"
454			"movl	4(%0),%%edx"
455			: : "r" (resp) : "eax", "edx");
456}
457
458ffi_status
459ffi_prep_raw_closure(
460	ffi_raw_closure*	closure,
461	ffi_cif*			cif,
462	void				(*fun)(ffi_cif*,void*,ffi_raw*,void*),
463	void*				user_data)
464{
465//	FFI_ASSERT (cif->abi == FFI_SYSV);
466	if (cif->abi != FFI_SYSV)
467		return FFI_BAD_ABI;
468
469	int i;
470
471/*	We currently don't support certain kinds of arguments for raw
472	closures.  This should be implemented by a separate assembly language
473	routine, since it would require argument processing, something we
474	don't do now for performance.	*/
475	for (i = cif->nargs - 1; i >= 0; i--)
476	{
477		FFI_ASSERT(cif->arg_types[i]->type != FFI_TYPE_STRUCT);
478		FFI_ASSERT(cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
479	}
480
481	FFI_INIT_TRAMPOLINE(closure->tramp, &ffi_closure_raw_SYSV, (void*)closure);
482
483	closure->cif		= cif;
484	closure->user_data	= user_data;
485	closure->fun		= fun;
486
487	return FFI_OK;
488}
489
490static void
491ffi_prep_args_raw(
492	char*			stack,
493	extended_cif*	ecif)
494{
495	memcpy(stack, ecif->avalue, ecif->cif->bytes);
496}
497
498/*	We borrow this routine from libffi (it must be changed, though, to
499	actually call the function passed in the first argument.  as of
500	libffi-1.20, this is not the case.)	*/
501//extern void
502//ffi_call_SYSV(
503//			void			(*)(char *, extended_cif *),
504///*@out@*/	extended_cif*	,
505//			unsigned		,
506//			unsigned		,
507//*@out@*/	unsigned*		,
508//			void			(*fn)());
509
510#ifdef X86_WIN32
511extern void
512ffi_call_STDCALL(
513			void			(*)(char *, extended_cif *),
514/*@out@*/	extended_cif*	,
515			unsigned		,
516			unsigned		,
517/*@out@*/	unsigned*		,
518			void			(*fn)());
519#endif // X86_WIN32
520
521void
522ffi_raw_call(
523/*@dependent@*/	ffi_cif*	cif,
524				void		(*fn)(),
525/*@out@*/		void*		rvalue,
526/*@dependent@*/	ffi_raw*	fake_avalue)
527{
528	extended_cif ecif;
529	void **avalue = (void **)fake_avalue;
530
531	ecif.cif = cif;
532	ecif.avalue = avalue;
533
534	/*	If the return value is a struct and we don't have a return
535		value address then we need to make one	*/
536	if ((rvalue == NULL) && retval_on_stack(cif->rtype))
537	{
538		/*@-sysunrecog@*/
539		ecif.rvalue = alloca(cif->rtype->size);
540		/*@=sysunrecog@*/
541	}
542	else
543		ecif.rvalue = rvalue;
544
545	switch (cif->abi)
546	{
547		case FFI_SYSV:
548			/*@-usedef@*/
549			ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes,
550				cif->flags, ecif.rvalue, fn);
551			/*@=usedef@*/
552			break;
553#ifdef X86_WIN32
554		case FFI_STDCALL:
555			/*@-usedef@*/
556			ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes,
557				cif->flags, ecif.rvalue, fn);
558			/*@=usedef@*/
559			break;
560#endif /* X86_WIN32 */
561		default:
562			FFI_ASSERT(0);
563			break;
564    }
565}
566
567#endif	// !FFI_NO_RAW_API
568//#endif	// !__x86_64__
569#endif	// __i386__
570