(root)/
gcc-13.2.0/
libffi/
src/
powerpc/
ffi.c
       1  /* -----------------------------------------------------------------------
       2     ffi.c - Copyright (C) 2013 IBM
       3             Copyright (C) 2011 Anthony Green
       4             Copyright (C) 2011 Kyle Moffett
       5             Copyright (C) 2008 Red Hat, Inc
       6             Copyright (C) 2007, 2008 Free Software Foundation, Inc
       7  	   Copyright (c) 1998 Geoffrey Keating
       8  
       9     PowerPC Foreign Function Interface
      10  
      11     Permission is hereby granted, free of charge, to any person obtaining
      12     a copy of this software and associated documentation files (the
      13     ``Software''), to deal in the Software without restriction, including
      14     without limitation the rights to use, copy, modify, merge, publish,
      15     distribute, sublicense, and/or sell copies of the Software, and to
      16     permit persons to whom the Software is furnished to do so, subject to
      17     the following conditions:
      18  
      19     The above copyright notice and this permission notice shall be included
      20     in all copies or substantial portions of the Software.
      21  
      22     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      25     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
      26     OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      27     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      28     OTHER DEALINGS IN THE SOFTWARE.
      29     ----------------------------------------------------------------------- */
      30  
      31  #include "ffi.h"
      32  #include "ffi_common.h"
      33  #include "ffi_powerpc.h"
      34  
      35  #if HAVE_LONG_DOUBLE_VARIANT
      36  /* Adjust ffi_type_longdouble.  */
      37  void FFI_HIDDEN
      38  ffi_prep_types (ffi_abi abi)
      39  {
      40  # if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
      41  #  ifdef POWERPC64
      42    ffi_prep_types_linux64 (abi);
      43  #  else
      44    ffi_prep_types_sysv (abi);
      45  #  endif
      46  # endif
      47  }
      48  #endif
      49  
      50  /* Perform machine dependent cif processing */
      51  ffi_status FFI_HIDDEN
      52  ffi_prep_cif_machdep (ffi_cif *cif)
      53  {
      54  #ifdef POWERPC64
      55    return ffi_prep_cif_linux64 (cif);
      56  #else
      57    return ffi_prep_cif_sysv (cif);
      58  #endif
      59  }
      60  
      61  ffi_status FFI_HIDDEN
      62  ffi_prep_cif_machdep_var (ffi_cif *cif,
      63  			  unsigned int nfixedargs MAYBE_UNUSED,
      64  			  unsigned int ntotalargs MAYBE_UNUSED)
      65  {
      66  #ifdef POWERPC64
      67    return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs);
      68  #else
      69    return ffi_prep_cif_sysv (cif);
      70  #endif
      71  }
      72  
      73  static void
      74  ffi_call_int (ffi_cif *cif,
      75  	      void (*fn) (void),
      76  	      void *rvalue,
      77  	      void **avalue,
      78  	      void *closure)
      79  {
      80    /* The final SYSV ABI says that structures smaller or equal 8 bytes
      81       are returned in r3/r4.  A draft ABI used by linux instead returns
      82       them in memory.
      83  
      84       We bounce-buffer SYSV small struct return values so that sysv.S
      85       can write r3 and r4 to memory without worrying about struct size.
      86     
      87       For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
      88       for similar reasons. This bounce buffer must be aligned to 16
      89       bytes for use with homogeneous structs of vectors (float128).  */
      90    float128 smst_buffer[8];
      91    extended_cif ecif;
      92  
      93    ecif.cif = cif;
      94    ecif.avalue = avalue;
      95  
      96    ecif.rvalue = rvalue;
      97    if ((cif->flags & FLAG_RETURNS_SMST) != 0)
      98      ecif.rvalue = smst_buffer;
      99    /* Ensure that we have a valid struct return value.
     100       FIXME: Isn't this just papering over a user problem?  */
     101    else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT)
     102      ecif.rvalue = alloca (cif->rtype->size);
     103  
     104  #ifdef POWERPC64
     105    ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure,
     106  		    -(long) cif->bytes);
     107  #else
     108    ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes);
     109  #endif
     110  
     111    /* Check for a bounce-buffered return value */
     112    if (rvalue && ecif.rvalue == smst_buffer)
     113      {
     114        unsigned int rsize = cif->rtype->size;
     115  #ifndef __LITTLE_ENDIAN__
     116        /* The SYSV ABI returns a structure of up to 4 bytes in size
     117  	 left-padded in r3.  */
     118  # ifndef POWERPC64
     119        if (rsize <= 4)
     120  	memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
     121        else
     122  # endif
     123  	/* The SYSV ABI returns a structure of up to 8 bytes in size
     124  	   left-padded in r3/r4, and the ELFv2 ABI similarly returns a
     125  	   structure of up to 8 bytes in size left-padded in r3. But
     126  	   note that a structure of a single float is not paddded.  */
     127  	if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0)
     128  	  memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
     129  	else
     130  #endif
     131  	  memcpy (rvalue, smst_buffer, rsize);
     132      }
     133  }
     134  
     135  void
     136  ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
     137  {
     138    ffi_call_int (cif, fn, rvalue, avalue, NULL);
     139  }
     140  
     141  void
     142  ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
     143  	     void *closure)
     144  {
     145    ffi_call_int (cif, fn, rvalue, avalue, closure);
     146  }
     147  
     148  ffi_status
     149  ffi_prep_closure_loc (ffi_closure *closure,
     150  		      ffi_cif *cif,
     151  		      void (*fun) (ffi_cif *, void *, void **, void *),
     152  		      void *user_data,
     153  		      void *codeloc)
     154  {
     155  #ifdef POWERPC64
     156    return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc);
     157  #else
     158    return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc);
     159  #endif
     160  }
     161  
     162  ffi_status
     163  ffi_prep_go_closure (ffi_go_closure *closure,
     164  		     ffi_cif *cif,
     165  		     void (*fun) (ffi_cif *, void *, void **, void *))
     166  {
     167  #ifdef POWERPC64
     168    closure->tramp = ffi_go_closure_linux64;
     169  #else
     170    closure->tramp = ffi_go_closure_sysv;
     171  #endif
     172    closure->cif = cif;
     173    closure->fun = fun;
     174    return FFI_OK;
     175  }