PageRenderTime 36ms CodeModel.GetById 2ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/Modules/_ctypes/libffi/src/s390/ffi.c

http://unladen-swallow.googlecode.com/
C | 780 lines | 484 code | 125 blank | 171 comment | 84 complexity | b03c7644ee96611457e7eed78b58a9c0 MD5 | raw file
  1/* -----------------------------------------------------------------------
  2   ffi.c - Copyright (c) 2000, 2007 Software AG
  3           Copyright (c) 2008 Red Hat, Inc
  4 
  5   S390 Foreign Function Interface
  6 
  7   Permission is hereby granted, free of charge, to any person obtaining
  8   a copy of this software and associated documentation files (the
  9   ``Software''), to deal in the Software without restriction, including
 10   without limitation the rights to use, copy, modify, merge, publish,
 11   distribute, sublicense, and/or sell copies of the Software, and to
 12   permit persons to whom the Software is furnished to do so, subject to
 13   the following conditions:
 14 
 15   The above copyright notice and this permission notice shall be included
 16   in all copies or substantial portions of the Software.
 17 
 18   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
 19   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 20   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 21   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
 22   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 23   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 24   OTHER DEALINGS IN THE SOFTWARE.
 25   ----------------------------------------------------------------------- */
 26/*====================================================================*/
 27/*                          Includes                                  */
 28/*                          --------                                  */
 29/*====================================================================*/
 30 
 31#include <ffi.h>
 32#include <ffi_common.h>
 33 
 34#include <stdlib.h>
 35#include <stdio.h>
 36 
 37/*====================== End of Includes =============================*/
 38 
 39/*====================================================================*/
 40/*                           Defines                                  */
 41/*                           -------                                  */
 42/*====================================================================*/
 43
 44/* Maximum number of GPRs available for argument passing.  */ 
 45#define MAX_GPRARGS 5
 46
 47/* Maximum number of FPRs available for argument passing.  */ 
 48#ifdef __s390x__
 49#define MAX_FPRARGS 4
 50#else
 51#define MAX_FPRARGS 2
 52#endif
 53
 54/* Round to multiple of 16.  */
 55#define ROUND_SIZE(size) (((size) + 15) & ~15)
 56
 57/* If these values change, sysv.S must be adapted!  */
 58#define FFI390_RET_VOID		0
 59#define FFI390_RET_STRUCT	1
 60#define FFI390_RET_FLOAT	2
 61#define FFI390_RET_DOUBLE	3
 62#define FFI390_RET_INT32	4
 63#define FFI390_RET_INT64	5
 64
 65/*===================== End of Defines ===============================*/
 66 
 67/*====================================================================*/
 68/*                          Prototypes                                */
 69/*                          ----------                                */
 70/*====================================================================*/
 71 
 72static void ffi_prep_args (unsigned char *, extended_cif *);
 73void
 74#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
 75__attribute__ ((visibility ("hidden")))
 76#endif
 77ffi_closure_helper_SYSV (ffi_closure *, unsigned long *, 
 78			 unsigned long long *, unsigned long *);
 79
 80/*====================== End of Prototypes ===========================*/
 81 
 82/*====================================================================*/
 83/*                          Externals                                 */
 84/*                          ---------                                 */
 85/*====================================================================*/
 86 
 87extern void ffi_call_SYSV(unsigned,
 88			  extended_cif *,
 89			  void (*)(unsigned char *, extended_cif *),
 90			  unsigned,
 91			  void *,
 92			  void (*fn)(void));
 93
 94extern void ffi_closure_SYSV(void);
 95 
 96/*====================== End of Externals ============================*/
 97 
 98/*====================================================================*/
 99/*                                                                    */
100/* Name     - ffi_check_struct_type.                                  */
101/*                                                                    */
102/* Function - Determine if a structure can be passed within a         */
103/*            general purpose or floating point register.             */
104/*                                                                    */
105/*====================================================================*/
106 
107static int
108ffi_check_struct_type (ffi_type *arg)
109{
110  size_t size = arg->size;
111
112  /* If the struct has just one element, look at that element
113     to find out whether to consider the struct as floating point.  */
114  while (arg->type == FFI_TYPE_STRUCT 
115         && arg->elements[0] && !arg->elements[1])
116    arg = arg->elements[0];
117
118  /* Structs of size 1, 2, 4, and 8 are passed in registers,
119     just like the corresponding int/float types.  */
120  switch (size)
121    {
122      case 1:
123        return FFI_TYPE_UINT8;
124
125      case 2:
126        return FFI_TYPE_UINT16;
127
128      case 4:
129	if (arg->type == FFI_TYPE_FLOAT)
130          return FFI_TYPE_FLOAT;
131	else
132	  return FFI_TYPE_UINT32;
133
134      case 8:
135	if (arg->type == FFI_TYPE_DOUBLE)
136          return FFI_TYPE_DOUBLE;
137	else
138	  return FFI_TYPE_UINT64;
139
140      default:
141	break;
142    }
143
144  /* Other structs are passed via a pointer to the data.  */
145  return FFI_TYPE_POINTER;
146}
147 
148/*======================== End of Routine ============================*/
149 
150/*====================================================================*/
151/*                                                                    */
152/* Name     - ffi_prep_args.                                          */
153/*                                                                    */
154/* Function - Prepare parameters for call to function.                */
155/*                                                                    */
156/* ffi_prep_args is called by the assembly routine once stack space   */
157/* has been allocated for the function's arguments.                   */
158/*                                                                    */
159/*====================================================================*/
160 
161static void
162ffi_prep_args (unsigned char *stack, extended_cif *ecif)
163{
164  /* The stack space will be filled with those areas:
165
166	FPR argument register save area     (highest addresses)
167	GPR argument register save area
168	temporary struct copies
169	overflow argument area              (lowest addresses)
170
171     We set up the following pointers:
172
173        p_fpr: bottom of the FPR area (growing upwards)
174	p_gpr: bottom of the GPR area (growing upwards)
175	p_ov: bottom of the overflow area (growing upwards)
176	p_struct: top of the struct copy area (growing downwards)
177
178     All areas are kept aligned to twice the word size.  */
179
180  int gpr_off = ecif->cif->bytes;
181  int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
182
183  unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
184  unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
185  unsigned char *p_struct = (unsigned char *)p_gpr;
186  unsigned long *p_ov = (unsigned long *)stack;
187
188  int n_fpr = 0;
189  int n_gpr = 0;
190  int n_ov = 0;
191
192  ffi_type **ptr;
193  void **p_argv = ecif->avalue;
194  int i;
195 
196  /* If we returning a structure then we set the first parameter register
197     to the address of where we are returning this structure.  */
198
199  if (ecif->cif->flags == FFI390_RET_STRUCT)
200    p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
201
202  /* Now for the arguments.  */
203 
204  for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
205       i > 0;
206       i--, ptr++, p_argv++)
207    {
208      void *arg = *p_argv;
209      int type = (*ptr)->type;
210
211#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
212      /* 16-byte long double is passed like a struct.  */
213      if (type == FFI_TYPE_LONGDOUBLE)
214	type = FFI_TYPE_STRUCT;
215#endif
216
217      /* Check how a structure type is passed.  */
218      if (type == FFI_TYPE_STRUCT)
219	{
220	  type = ffi_check_struct_type (*ptr);
221
222	  /* If we pass the struct via pointer, copy the data.  */
223	  if (type == FFI_TYPE_POINTER)
224	    {
225	      p_struct -= ROUND_SIZE ((*ptr)->size);
226	      memcpy (p_struct, (char *)arg, (*ptr)->size);
227	      arg = &p_struct;
228	    }
229	}
230
231      /* Now handle all primitive int/pointer/float data types.  */
232      switch (type) 
233	{
234	  case FFI_TYPE_DOUBLE:
235	    if (n_fpr < MAX_FPRARGS)
236	      p_fpr[n_fpr++] = *(unsigned long long *) arg;
237	    else
238#ifdef __s390x__
239	      p_ov[n_ov++] = *(unsigned long *) arg;
240#else
241	      p_ov[n_ov++] = ((unsigned long *) arg)[0],
242	      p_ov[n_ov++] = ((unsigned long *) arg)[1];
243#endif
244	    break;
245	
246	  case FFI_TYPE_FLOAT:
247	    if (n_fpr < MAX_FPRARGS)
248	      p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
249	    else
250	      p_ov[n_ov++] = *(unsigned int *) arg;
251	    break;
252
253	  case FFI_TYPE_POINTER:
254	    if (n_gpr < MAX_GPRARGS)
255	      p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
256	    else
257	      p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
258	    break;
259 
260	  case FFI_TYPE_UINT64:
261	  case FFI_TYPE_SINT64:
262#ifdef __s390x__
263	    if (n_gpr < MAX_GPRARGS)
264	      p_gpr[n_gpr++] = *(unsigned long *) arg;
265	    else
266	      p_ov[n_ov++] = *(unsigned long *) arg;
267#else
268	    if (n_gpr == MAX_GPRARGS-1)
269	      n_gpr = MAX_GPRARGS;
270	    if (n_gpr < MAX_GPRARGS)
271	      p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
272	      p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
273	    else
274	      p_ov[n_ov++] = ((unsigned long *) arg)[0],
275	      p_ov[n_ov++] = ((unsigned long *) arg)[1];
276#endif
277	    break;
278 
279	  case FFI_TYPE_UINT32:
280	    if (n_gpr < MAX_GPRARGS)
281	      p_gpr[n_gpr++] = *(unsigned int *) arg;
282	    else
283	      p_ov[n_ov++] = *(unsigned int *) arg;
284	    break;
285 
286	  case FFI_TYPE_INT:
287	  case FFI_TYPE_SINT32:
288	    if (n_gpr < MAX_GPRARGS)
289	      p_gpr[n_gpr++] = *(signed int *) arg;
290	    else
291	      p_ov[n_ov++] = *(signed int *) arg;
292	    break;
293 
294	  case FFI_TYPE_UINT16:
295	    if (n_gpr < MAX_GPRARGS)
296	      p_gpr[n_gpr++] = *(unsigned short *) arg;
297	    else
298	      p_ov[n_ov++] = *(unsigned short *) arg;
299	    break;
300 
301	  case FFI_TYPE_SINT16:
302	    if (n_gpr < MAX_GPRARGS)
303	      p_gpr[n_gpr++] = *(signed short *) arg;
304	    else
305	      p_ov[n_ov++] = *(signed short *) arg;
306	    break;
307
308	  case FFI_TYPE_UINT8:
309	    if (n_gpr < MAX_GPRARGS)
310	      p_gpr[n_gpr++] = *(unsigned char *) arg;
311	    else
312	      p_ov[n_ov++] = *(unsigned char *) arg;
313	    break;
314 
315	  case FFI_TYPE_SINT8:
316	    if (n_gpr < MAX_GPRARGS)
317	      p_gpr[n_gpr++] = *(signed char *) arg;
318	    else
319	      p_ov[n_ov++] = *(signed char *) arg;
320	    break;
321 
322	  default:
323	    FFI_ASSERT (0);
324	    break;
325        }
326    }
327}
328
329/*======================== End of Routine ============================*/
330 
331/*====================================================================*/
332/*                                                                    */
333/* Name     - ffi_prep_cif_machdep.                                   */
334/*                                                                    */
335/* Function - Perform machine dependent CIF processing.               */
336/*                                                                    */
337/*====================================================================*/
338 
339ffi_status
340ffi_prep_cif_machdep(ffi_cif *cif)
341{
342  size_t struct_size = 0;
343  int n_gpr = 0;
344  int n_fpr = 0;
345  int n_ov = 0;
346
347  ffi_type **ptr;
348  int i;
349
350  /* Determine return value handling.  */ 
351
352  switch (cif->rtype->type)
353    {
354      /* Void is easy.  */
355      case FFI_TYPE_VOID:
356	cif->flags = FFI390_RET_VOID;
357	break;
358
359      /* Structures are returned via a hidden pointer.  */
360      case FFI_TYPE_STRUCT:
361	cif->flags = FFI390_RET_STRUCT;
362	n_gpr++;  /* We need one GPR to pass the pointer.  */
363	break; 
364
365      /* Floating point values are returned in fpr 0.  */
366      case FFI_TYPE_FLOAT:
367	cif->flags = FFI390_RET_FLOAT;
368	break;
369
370      case FFI_TYPE_DOUBLE:
371	cif->flags = FFI390_RET_DOUBLE;
372	break;
373
374#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
375      case FFI_TYPE_LONGDOUBLE:
376	cif->flags = FFI390_RET_STRUCT;
377	n_gpr++;
378	break;
379#endif
380      /* Integer values are returned in gpr 2 (and gpr 3
381	 for 64-bit values on 31-bit machines).  */
382      case FFI_TYPE_UINT64:
383      case FFI_TYPE_SINT64:
384	cif->flags = FFI390_RET_INT64;
385	break;
386
387      case FFI_TYPE_POINTER:
388      case FFI_TYPE_INT:
389      case FFI_TYPE_UINT32:
390      case FFI_TYPE_SINT32:
391      case FFI_TYPE_UINT16:
392      case FFI_TYPE_SINT16:
393      case FFI_TYPE_UINT8:
394      case FFI_TYPE_SINT8:
395	/* These are to be extended to word size.  */
396#ifdef __s390x__
397	cif->flags = FFI390_RET_INT64;
398#else
399	cif->flags = FFI390_RET_INT32;
400#endif
401	break;
402 
403      default:
404        FFI_ASSERT (0);
405        break;
406    }
407
408  /* Now for the arguments.  */
409 
410  for (ptr = cif->arg_types, i = cif->nargs;
411       i > 0;
412       i--, ptr++)
413    {
414      int type = (*ptr)->type;
415
416#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
417      /* 16-byte long double is passed like a struct.  */
418      if (type == FFI_TYPE_LONGDOUBLE)
419	type = FFI_TYPE_STRUCT;
420#endif
421
422      /* Check how a structure type is passed.  */
423      if (type == FFI_TYPE_STRUCT)
424	{
425	  type = ffi_check_struct_type (*ptr);
426
427	  /* If we pass the struct via pointer, we must reserve space
428	     to copy its data for proper call-by-value semantics.  */
429	  if (type == FFI_TYPE_POINTER)
430	    struct_size += ROUND_SIZE ((*ptr)->size);
431	}
432
433      /* Now handle all primitive int/float data types.  */
434      switch (type) 
435	{
436	  /* The first MAX_FPRARGS floating point arguments
437	     go in FPRs, the rest overflow to the stack.  */
438
439	  case FFI_TYPE_DOUBLE:
440	    if (n_fpr < MAX_FPRARGS)
441	      n_fpr++;
442	    else
443	      n_ov += sizeof (double) / sizeof (long);
444	    break;
445	
446	  case FFI_TYPE_FLOAT:
447	    if (n_fpr < MAX_FPRARGS)
448	      n_fpr++;
449	    else
450	      n_ov++;
451	    break;
452
453	  /* On 31-bit machines, 64-bit integers are passed in GPR pairs,
454	     if one is still available, or else on the stack.  If only one
455	     register is free, skip the register (it won't be used for any 
456	     subsequent argument either).  */
457	      
458#ifndef __s390x__
459	  case FFI_TYPE_UINT64:
460	  case FFI_TYPE_SINT64:
461	    if (n_gpr == MAX_GPRARGS-1)
462	      n_gpr = MAX_GPRARGS;
463	    if (n_gpr < MAX_GPRARGS)
464	      n_gpr += 2;
465	    else
466	      n_ov += 2;
467	    break;
468#endif
469
470	  /* Everything else is passed in GPRs (until MAX_GPRARGS
471	     have been used) or overflows to the stack.  */
472
473	  default: 
474	    if (n_gpr < MAX_GPRARGS)
475	      n_gpr++;
476	    else
477	      n_ov++;
478	    break;
479        }
480    }
481
482  /* Total stack space as required for overflow arguments
483     and temporary structure copies.  */
484
485  cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
486 
487  return FFI_OK;
488}
489 
490/*======================== End of Routine ============================*/
491 
492/*====================================================================*/
493/*                                                                    */
494/* Name     - ffi_call.                                               */
495/*                                                                    */
496/* Function - Call the FFI routine.                                   */
497/*                                                                    */
498/*====================================================================*/
499 
500void
501ffi_call(ffi_cif *cif,
502	 void (*fn)(void),
503	 void *rvalue,
504	 void **avalue)
505{
506  int ret_type = cif->flags;
507  extended_cif ecif;
508 
509  ecif.cif    = cif;
510  ecif.avalue = avalue;
511  ecif.rvalue = rvalue;
512
513  /* If we don't have a return value, we need to fake one.  */
514  if (rvalue == NULL)
515    {
516      if (ret_type == FFI390_RET_STRUCT)
517	ecif.rvalue = alloca (cif->rtype->size);
518      else
519	ret_type = FFI390_RET_VOID;
520    } 
521
522  switch (cif->abi)
523    {
524      case FFI_SYSV:
525        ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
526		       ret_type, ecif.rvalue, fn);
527        break;
528 
529      default:
530        FFI_ASSERT (0);
531        break;
532    }
533}
534 
535/*======================== End of Routine ============================*/
536
537/*====================================================================*/
538/*                                                                    */
539/* Name     - ffi_closure_helper_SYSV.                                */
540/*                                                                    */
541/* Function - Call a FFI closure target function.                     */
542/*                                                                    */
543/*====================================================================*/
544 
545void
546ffi_closure_helper_SYSV (ffi_closure *closure,
547			 unsigned long *p_gpr,
548			 unsigned long long *p_fpr,
549			 unsigned long *p_ov)
550{
551  unsigned long long ret_buffer;
552
553  void *rvalue = &ret_buffer;
554  void **avalue;
555  void **p_arg;
556
557  int n_gpr = 0;
558  int n_fpr = 0;
559  int n_ov = 0;
560
561  ffi_type **ptr;
562  int i;
563
564  /* Allocate buffer for argument list pointers.  */
565
566  p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
567
568  /* If we returning a structure, pass the structure address 
569     directly to the target function.  Otherwise, have the target 
570     function store the return value to the GPR save area.  */
571
572  if (closure->cif->flags == FFI390_RET_STRUCT)
573    rvalue = (void *) p_gpr[n_gpr++];
574
575  /* Now for the arguments.  */
576
577  for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
578       i > 0;
579       i--, p_arg++, ptr++)
580    {
581      int deref_struct_pointer = 0;
582      int type = (*ptr)->type;
583
584#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
585      /* 16-byte long double is passed like a struct.  */
586      if (type == FFI_TYPE_LONGDOUBLE)
587	type = FFI_TYPE_STRUCT;
588#endif
589
590      /* Check how a structure type is passed.  */
591      if (type == FFI_TYPE_STRUCT)
592	{
593	  type = ffi_check_struct_type (*ptr);
594
595	  /* If we pass the struct via pointer, remember to 
596	     retrieve the pointer later.  */
597	  if (type == FFI_TYPE_POINTER)
598	    deref_struct_pointer = 1;
599	}
600
601      /* Pointers are passed like UINTs of the same size.  */
602      if (type == FFI_TYPE_POINTER)
603#ifdef __s390x__
604	type = FFI_TYPE_UINT64;
605#else
606	type = FFI_TYPE_UINT32;
607#endif
608
609      /* Now handle all primitive int/float data types.  */
610      switch (type) 
611	{
612	  case FFI_TYPE_DOUBLE:
613	    if (n_fpr < MAX_FPRARGS)
614	      *p_arg = &p_fpr[n_fpr++];
615	    else
616	      *p_arg = &p_ov[n_ov], 
617	      n_ov += sizeof (double) / sizeof (long);
618	    break;
619	
620	  case FFI_TYPE_FLOAT:
621	    if (n_fpr < MAX_FPRARGS)
622	      *p_arg = &p_fpr[n_fpr++];
623	    else
624	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
625	    break;
626 
627	  case FFI_TYPE_UINT64:
628	  case FFI_TYPE_SINT64:
629#ifdef __s390x__
630	    if (n_gpr < MAX_GPRARGS)
631	      *p_arg = &p_gpr[n_gpr++];
632	    else
633	      *p_arg = &p_ov[n_ov++];
634#else
635	    if (n_gpr == MAX_GPRARGS-1)
636	      n_gpr = MAX_GPRARGS;
637	    if (n_gpr < MAX_GPRARGS)
638	      *p_arg = &p_gpr[n_gpr], n_gpr += 2;
639	    else
640	      *p_arg = &p_ov[n_ov], n_ov += 2;
641#endif
642	    break;
643 
644	  case FFI_TYPE_INT:
645	  case FFI_TYPE_UINT32:
646	  case FFI_TYPE_SINT32:
647	    if (n_gpr < MAX_GPRARGS)
648	      *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
649	    else
650	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
651	    break;
652 
653	  case FFI_TYPE_UINT16:
654	  case FFI_TYPE_SINT16:
655	    if (n_gpr < MAX_GPRARGS)
656	      *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
657	    else
658	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
659	    break;
660
661	  case FFI_TYPE_UINT8:
662	  case FFI_TYPE_SINT8:
663	    if (n_gpr < MAX_GPRARGS)
664	      *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
665	    else
666	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
667	    break;
668 
669	  default:
670	    FFI_ASSERT (0);
671	    break;
672        }
673
674      /* If this is a struct passed via pointer, we need to
675	 actually retrieve that pointer.  */
676      if (deref_struct_pointer)
677	*p_arg = *(void **)*p_arg;
678    }
679
680
681  /* Call the target function.  */
682  (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
683
684  /* Convert the return value.  */
685  switch (closure->cif->rtype->type)
686    {
687      /* Void is easy, and so is struct.  */
688      case FFI_TYPE_VOID:
689      case FFI_TYPE_STRUCT:
690#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
691      case FFI_TYPE_LONGDOUBLE:
692#endif
693	break;
694
695      /* Floating point values are returned in fpr 0.  */
696      case FFI_TYPE_FLOAT:
697	p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
698	break;
699
700      case FFI_TYPE_DOUBLE:
701	p_fpr[0] = *(unsigned long long *) rvalue;
702	break;
703
704      /* Integer values are returned in gpr 2 (and gpr 3
705	 for 64-bit values on 31-bit machines).  */
706      case FFI_TYPE_UINT64:
707      case FFI_TYPE_SINT64:
708#ifdef __s390x__
709	p_gpr[0] = *(unsigned long *) rvalue;
710#else
711	p_gpr[0] = ((unsigned long *) rvalue)[0],
712	p_gpr[1] = ((unsigned long *) rvalue)[1];
713#endif
714	break;
715
716      case FFI_TYPE_POINTER:
717      case FFI_TYPE_UINT32:
718      case FFI_TYPE_UINT16:
719      case FFI_TYPE_UINT8:
720	p_gpr[0] = *(unsigned long *) rvalue;
721	break;
722
723      case FFI_TYPE_INT:
724      case FFI_TYPE_SINT32:
725      case FFI_TYPE_SINT16:
726      case FFI_TYPE_SINT8:
727	p_gpr[0] = *(signed long *) rvalue;
728	break;
729
730      default:
731        FFI_ASSERT (0);
732        break;
733    }
734}
735 
736/*======================== End of Routine ============================*/
737
738/*====================================================================*/
739/*                                                                    */
740/* Name     - ffi_prep_closure_loc.                                   */
741/*                                                                    */
742/* Function - Prepare a FFI closure.                                  */
743/*                                                                    */
744/*====================================================================*/
745 
746ffi_status
747ffi_prep_closure_loc (ffi_closure *closure,
748		      ffi_cif *cif,
749		      void (*fun) (ffi_cif *, void *, void **, void *),
750		      void *user_data,
751		      void *codeloc)
752{
753  FFI_ASSERT (cif->abi == FFI_SYSV);
754
755#ifndef __s390x__
756  *(short *)&closure->tramp [0] = 0x0d10;   /* basr %r1,0 */
757  *(short *)&closure->tramp [2] = 0x9801;   /* lm %r0,%r1,6(%r1) */
758  *(short *)&closure->tramp [4] = 0x1006;
759  *(short *)&closure->tramp [6] = 0x07f1;   /* br %r1 */
760  *(long  *)&closure->tramp [8] = (long)codeloc;
761  *(long  *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
762#else
763  *(short *)&closure->tramp [0] = 0x0d10;   /* basr %r1,0 */
764  *(short *)&closure->tramp [2] = 0xeb01;   /* lmg %r0,%r1,14(%r1) */
765  *(short *)&closure->tramp [4] = 0x100e;
766  *(short *)&closure->tramp [6] = 0x0004;
767  *(short *)&closure->tramp [8] = 0x07f1;   /* br %r1 */
768  *(long  *)&closure->tramp[16] = (long)codeloc;
769  *(long  *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
770#endif 
771 
772  closure->cif = cif;
773  closure->user_data = user_data;
774  closure->fun = fun;
775 
776  return FFI_OK;
777}
778
779/*======================== End of Routine ============================*/
780