(root)/
gcc-13.2.0/
libffi/
src/
moxie/
ffi.c
       1  /* -----------------------------------------------------------------------
       2     ffi.c - Copyright (C) 2012, 2013, 2018  Anthony Green
       3     
       4     Moxie Foreign Function Interface 
       5  
       6     Permission is hereby granted, free of charge, to any person obtaining
       7     a copy of this software and associated documentation files (the
       8     ``Software''), to deal in the Software without restriction, including
       9     without limitation the rights to use, copy, modify, merge, publish,
      10     distribute, sublicense, and/or sell copies of the Software, and to
      11     permit persons to whom the Software is furnished to do so, subject to
      12     the following conditions:
      13  
      14     The above copyright notice and this permission notice shall be included
      15     in all copies or substantial portions of the Software.
      16  
      17     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
      18     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      19     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      20     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      21     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      22     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      24     DEALINGS IN THE SOFTWARE.
      25     ----------------------------------------------------------------------- */
      26  
      27  #include <ffi.h>
      28  #include <ffi_common.h>
      29  
      30  #include <stdlib.h>
      31  
      32  /* ffi_prep_args is called by the assembly routine once stack space
      33     has been allocated for the function's arguments */
      34  
      35  void *ffi_prep_args(char *stack, extended_cif *ecif)
      36  {
      37    register unsigned int i;
      38    register void **p_argv;
      39    register char *argp;
      40    register ffi_type **p_arg;
      41    register int count = 0;
      42  
      43    p_argv = ecif->avalue;
      44    argp = stack;
      45  
      46    if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
      47      {
      48        *(void **) argp = ecif->rvalue;
      49        argp += 4;
      50      }
      51  
      52    for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
      53         (i != 0);
      54         i--, p_arg++)
      55      {
      56        size_t z;
      57        
      58        z = (*p_arg)->size;
      59  
      60        if ((*p_arg)->type == FFI_TYPE_STRUCT)
      61  	{
      62  	  z = sizeof(void*);
      63  	  *(void **) argp = *p_argv;
      64  	} 
      65        else if (z < sizeof(int))
      66  	{
      67  	  z = sizeof(int);
      68  	  switch ((*p_arg)->type)
      69  	    {
      70  	    case FFI_TYPE_SINT8:
      71  	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
      72  	      break;
      73  	      
      74  	    case FFI_TYPE_UINT8:
      75  	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
      76  	      break;
      77  	      
      78  	    case FFI_TYPE_SINT16:
      79  	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
      80  	      break;
      81  		  
      82  	    case FFI_TYPE_UINT16:
      83  	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
      84  	      break;
      85  		  
      86  	    default:
      87  	      FFI_ASSERT(0);
      88  	    }
      89  	}
      90        else if (z == sizeof(int))
      91  	{
      92  	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
      93  	}
      94        else
      95  	{
      96  	  memcpy(argp, *p_argv, z);
      97  	}
      98        p_argv++;
      99        argp += z;
     100        count += z;
     101      }
     102  
     103    return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
     104  }
     105  
     106  /* Perform machine dependent cif processing */
     107  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     108  {
     109    if (cif->rtype->type == FFI_TYPE_STRUCT)
     110      cif->flags = -1;
     111    else
     112      cif->flags = cif->rtype->size;
     113  
     114    cif->bytes = FFI_ALIGN (cif->bytes, 8);
     115  
     116    return FFI_OK;
     117  }
     118  
     119  extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
     120  			  extended_cif *, 
     121  			  unsigned, unsigned, 
     122  			  unsigned *, 
     123  			  void (*fn)(void));
     124  
     125  void ffi_call(ffi_cif *cif, 
     126  	      void (*fn)(void), 
     127  	      void *rvalue, 
     128  	      void **avalue)
     129  {
     130    extended_cif ecif;
     131  
     132    ecif.cif = cif;
     133    ecif.avalue = avalue;
     134    
     135    /* If the return value is a struct and we don't have a return	*/
     136    /* value address then we need to make one		        */
     137  
     138    if ((rvalue == NULL) && 
     139        (cif->rtype->type == FFI_TYPE_STRUCT))
     140      {
     141        ecif.rvalue = alloca(cif->rtype->size);
     142      }
     143    else
     144      ecif.rvalue = rvalue;
     145  
     146    switch (cif->abi) 
     147      {
     148      case FFI_EABI:
     149        ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
     150  		    cif->flags, ecif.rvalue, fn);
     151        break;
     152      default:
     153        FFI_ASSERT(0);
     154        break;
     155      }
     156  }
     157  
     158  void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
     159  		       unsigned arg4, unsigned arg5, unsigned arg6)
     160  {
     161    /* This function is called by a trampoline.  The trampoline stows a
     162       pointer to the ffi_closure object in $r12.  We must save this
     163       pointer in a place that will persist while we do our work.  */
     164    register ffi_closure *creg __asm__ ("$r12");
     165    ffi_closure *closure = creg;
     166  
     167    /* Arguments that don't fit in registers are found on the stack
     168       at a fixed offset above the current frame pointer.  */
     169    register char *frame_pointer __asm__ ("$fp");
     170  
     171    /* Pointer to a struct return value.  */
     172    void *struct_rvalue = (void *) arg1;
     173  
     174    /* 6 words reserved for register args + 3 words from jsr */
     175    char *stack_args = frame_pointer + 9*4; 
     176  
     177    /* Lay the register arguments down in a continuous chunk of memory.  */
     178    unsigned register_args[6] =
     179      { arg1, arg2, arg3, arg4, arg5, arg6 };
     180    char *register_args_ptr = (char *) register_args;
     181  
     182    ffi_cif *cif = closure->cif;
     183    ffi_type **arg_types = cif->arg_types;
     184    void **avalue = alloca (cif->nargs * sizeof(void *));
     185    char *ptr = (char *) register_args;
     186    int i;
     187  
     188    /* preserve struct type return pointer passing */
     189    if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
     190      ptr += 4;
     191      register_args_ptr = (char *)&register_args[1];
     192    }
     193  
     194    /* Find the address of each argument.  */
     195    for (i = 0; i < cif->nargs; i++)
     196      {
     197        switch (arg_types[i]->type)
     198  	{
     199  	case FFI_TYPE_SINT8:
     200  	case FFI_TYPE_UINT8:
     201  	  avalue[i] = ptr + 3;
     202  	  break;
     203  	case FFI_TYPE_SINT16:
     204  	case FFI_TYPE_UINT16:
     205  	  avalue[i] = ptr + 2;
     206  	  break;
     207  	case FFI_TYPE_SINT32:
     208  	case FFI_TYPE_UINT32:
     209  	case FFI_TYPE_FLOAT:
     210  	case FFI_TYPE_POINTER:
     211  	  avalue[i] = ptr;
     212  	  break;
     213  	case FFI_TYPE_STRUCT:
     214  	  avalue[i] = *(void**)ptr;
     215  	  break;
     216  	default:
     217  	  /* This is an 8-byte value.  */
     218  	  if (ptr == (char *) &register_args[5])
     219  	    {
     220  	      /* The value is split across two locations */
     221  	      unsigned *ip = alloca(8);
     222  	      avalue[i] = ip;
     223  	      ip[0] = *(unsigned *) ptr;
     224  	      ip[1] = *(unsigned *) stack_args;
     225  	    }
     226  	  else
     227  	    {
     228  	      avalue[i] = ptr;
     229  	    }
     230  	  ptr += 4;
     231  	  break;
     232  	}
     233        ptr += 4;
     234  
     235        /* If we've handled more arguments than fit in registers,
     236  	 start looking at the those passed on the stack.  */
     237        if (ptr == (char *) &register_args[6])
     238  	ptr = stack_args;
     239        else if (ptr == (char *) &register_args[7])
     240  	ptr = stack_args + 4;
     241      }
     242  
     243    /* Invoke the closure.  */
     244    if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
     245      {
     246        (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
     247      }
     248    else
     249      {
     250        /* Allocate space for the return value and call the function.  */
     251        long long rvalue;
     252        (closure->fun) (cif, &rvalue, avalue, closure->user_data);
     253        asm ("mov $r12, %0\n ld.l $r0, ($r12)\n ldo.l $r1, 4($r12)" : : "r" (&rvalue));
     254      }
     255  }
     256  
     257  ffi_status
     258  ffi_prep_closure_loc (ffi_closure* closure,
     259  		      ffi_cif* cif,
     260  		      void (*fun)(ffi_cif*, void*, void**, void*),
     261  		      void *user_data,
     262  		      void *codeloc)
     263  {
     264    unsigned short *tramp = (unsigned short *) &closure->tramp[0];
     265    unsigned long fn = (long) ffi_closure_eabi;
     266    unsigned long cls = (long) codeloc;
     267  
     268    if (cif->abi != FFI_EABI)
     269      return FFI_BAD_ABI;
     270  
     271    fn = (unsigned long) ffi_closure_eabi;
     272  
     273    tramp[0] = 0x01e0; /* ldi.l $r12, .... */
     274    tramp[1] = cls >> 16;
     275    tramp[2] = cls & 0xffff;
     276    tramp[3] = 0x1a00; /* jmpa .... */
     277    tramp[4] = fn >> 16;
     278    tramp[5] = fn & 0xffff;
     279  
     280    closure->cif = cif;
     281    closure->fun = fun;
     282    closure->user_data = user_data;
     283  
     284    return FFI_OK;
     285  }