Add Meta processor support
This commit is contained in:
@@ -2,6 +2,15 @@
|
|||||||
|
|
||||||
* src/x86/ffi.c (ffi_prep_cif_machdep): Always align stack.
|
* src/x86/ffi.c (ffi_prep_cif_machdep): Always align stack.
|
||||||
|
|
||||||
|
2013-03-13 Markos Chandras <markos.chandras@imgtec.com>
|
||||||
|
|
||||||
|
* configure.ac: Add support for Imagination Technologies Meta.
|
||||||
|
* Makefile.am: Likewise.
|
||||||
|
* README: Add Imagination Technologies Meta details.
|
||||||
|
* src/metag/ffi.c: New.
|
||||||
|
* src/metag/ffitarget.h: Likewise.
|
||||||
|
* src/metag/sysv.S: Likewise.
|
||||||
|
|
||||||
2013-02-11 Anthony Green <green@moxielogic.com>
|
2013-02-11 Anthony Green <green@moxielogic.com>
|
||||||
|
|
||||||
* configure.ac: Update release number to 3.0.12.
|
* configure.ac: Update release number to 3.0.12.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \
|
|||||||
src/frv/ffitarget.h src/dlmalloc.c src/tile/ffi.c \
|
src/frv/ffitarget.h src/dlmalloc.c src/tile/ffi.c \
|
||||||
src/tile/ffitarget.h src/tile/tile.S libtool-version \
|
src/tile/ffitarget.h src/tile/tile.S libtool-version \
|
||||||
src/xtensa/ffitarget.h src/xtensa/ffi.c src/xtensa/sysv.S \
|
src/xtensa/ffitarget.h src/xtensa/ffi.c src/xtensa/sysv.S \
|
||||||
|
src/metag/ffi.c src/metag/ffitarget.h src/metag/sysv.S \
|
||||||
ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \
|
ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \
|
||||||
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \
|
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \
|
||||||
m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \
|
m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \
|
||||||
@@ -208,6 +209,9 @@ endif
|
|||||||
if XTENSA
|
if XTENSA
|
||||||
nodist_libffi_la_SOURCES += src/xtensa/sysv.S src/xtensa/ffi.c
|
nodist_libffi_la_SOURCES += src/xtensa/sysv.S src/xtensa/ffi.c
|
||||||
endif
|
endif
|
||||||
|
if METAG
|
||||||
|
nodist_libffi_la_SOURCES += src/metag/sysv.S src/metag/ffi.c
|
||||||
|
endif
|
||||||
|
|
||||||
libffi_convenience_la_SOURCES = $(libffi_la_SOURCES)
|
libffi_convenience_la_SOURCES = $(libffi_la_SOURCES)
|
||||||
nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
|
nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
|
||||||
|
|||||||
8
README
8
README
@@ -1,7 +1,7 @@
|
|||||||
Status
|
Status
|
||||||
======
|
======
|
||||||
|
|
||||||
libffi-3.0.12 was released on February 11, 2013. Check the libffi web
|
libffi-3.0.13 was released on March 16, 2013. Check the libffi web
|
||||||
page for updates: <URL:http://sourceware.org/libffi/>.
|
page for updates: <URL:http://sourceware.org/libffi/>.
|
||||||
|
|
||||||
|
|
||||||
@@ -63,6 +63,7 @@ tested:
|
|||||||
| M68K | FreeMiNT | GCC |
|
| M68K | FreeMiNT | GCC |
|
||||||
| M68K | Linux | GCC |
|
| M68K | Linux | GCC |
|
||||||
| M68K | RTEMS | GCC |
|
| M68K | RTEMS | GCC |
|
||||||
|
| Meta | Linux | GCC |
|
||||||
| MicroBlaze | Linux | GCC |
|
| MicroBlaze | Linux | GCC |
|
||||||
| MIPS | IRIX | GCC |
|
| MIPS | IRIX | GCC |
|
||||||
| MIPS | Linux | GCC |
|
| MIPS | Linux | GCC |
|
||||||
@@ -162,6 +163,11 @@ History
|
|||||||
|
|
||||||
See the ChangeLog files for details.
|
See the ChangeLog files for details.
|
||||||
|
|
||||||
|
3.0.13 Mar-16-13
|
||||||
|
|
||||||
|
Add Meta support.
|
||||||
|
Fix stack alignment bug on 32-bit x86.
|
||||||
|
|
||||||
3.0.12 Feb-11-13
|
3.0.12 Feb-11-13
|
||||||
Add Moxie support.
|
Add Moxie support.
|
||||||
Add AArch64 support.
|
Add AArch64 support.
|
||||||
|
|||||||
@@ -199,6 +199,10 @@ case "$host" in
|
|||||||
TARGET=MOXIE; TARGETDIR=moxie
|
TARGET=MOXIE; TARGETDIR=moxie
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
metag-*-*)
|
||||||
|
TARGET=METAG; TARGETDIR=metag
|
||||||
|
;;
|
||||||
|
|
||||||
mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
|
mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
|
||||||
TARGET=MIPS; TARGETDIR=mips
|
TARGET=MIPS; TARGETDIR=mips
|
||||||
;;
|
;;
|
||||||
@@ -278,6 +282,7 @@ AM_CONDITIONAL(IA64, test x$TARGET = xIA64)
|
|||||||
AM_CONDITIONAL(M32R, test x$TARGET = xM32R)
|
AM_CONDITIONAL(M32R, test x$TARGET = xM32R)
|
||||||
AM_CONDITIONAL(M68K, test x$TARGET = xM68K)
|
AM_CONDITIONAL(M68K, test x$TARGET = xM68K)
|
||||||
AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
|
AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
|
||||||
|
AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
|
||||||
AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
|
AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
|
||||||
AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
|
AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
|
||||||
AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
|
AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
|
||||||
|
|||||||
330
src/metag/ffi.c
Normal file
330
src/metag/ffi.c
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
ffi.c - Copyright (c) 2013 Imagination Technologies
|
||||||
|
|
||||||
|
Meta Foreign Function Interface
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
`Software''), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED `AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <ffi.h>
|
||||||
|
#include <ffi_common.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ffi_prep_args is called by the assembly routine once stack space has been
|
||||||
|
* allocated for the function's arguments
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
|
||||||
|
{
|
||||||
|
register unsigned int i;
|
||||||
|
register void **p_argv;
|
||||||
|
register char *argp;
|
||||||
|
register ffi_type **p_arg;
|
||||||
|
|
||||||
|
argp = stack;
|
||||||
|
|
||||||
|
/* Store return value */
|
||||||
|
if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
|
||||||
|
argp -= 4;
|
||||||
|
*(void **) argp = ecif->rvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_argv = ecif->avalue;
|
||||||
|
|
||||||
|
/* point to next location */
|
||||||
|
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++)
|
||||||
|
{
|
||||||
|
size_t z;
|
||||||
|
|
||||||
|
/* Move argp to address of argument */
|
||||||
|
z = (*p_arg)->size;
|
||||||
|
argp -= z;
|
||||||
|
|
||||||
|
/* Align if necessary */
|
||||||
|
argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
|
||||||
|
|
||||||
|
if (z < sizeof(int)) {
|
||||||
|
z = sizeof(int);
|
||||||
|
switch ((*p_arg)->type)
|
||||||
|
{
|
||||||
|
case FFI_TYPE_SINT8:
|
||||||
|
*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
|
||||||
|
break;
|
||||||
|
case FFI_TYPE_UINT8:
|
||||||
|
*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
|
||||||
|
break;
|
||||||
|
case FFI_TYPE_SINT16:
|
||||||
|
*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
|
||||||
|
break;
|
||||||
|
case FFI_TYPE_UINT16:
|
||||||
|
*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
|
||||||
|
case FFI_TYPE_STRUCT:
|
||||||
|
memcpy(argp, *p_argv, (*p_arg)->size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FFI_ASSERT(0);
|
||||||
|
}
|
||||||
|
} else if ( z == sizeof(int)) {
|
||||||
|
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
|
||||||
|
} else {
|
||||||
|
memcpy(argp, *p_argv, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the size of the arguments to be passed in registers,
|
||||||
|
padded to an 8 byte boundary to preserve stack alignment */
|
||||||
|
return ALIGN(MIN(stack - argp, 6*4), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform machine dependent cif processing */
|
||||||
|
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
|
{
|
||||||
|
ffi_type **ptr;
|
||||||
|
unsigned i, bytes = 0;
|
||||||
|
|
||||||
|
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) {
|
||||||
|
if ((*ptr)->size == 0)
|
||||||
|
return FFI_BAD_TYPEDEF;
|
||||||
|
|
||||||
|
/* Perform a sanity check on the argument type, do this
|
||||||
|
check after the initialization. */
|
||||||
|
FFI_ASSERT_VALID_TYPE(*ptr);
|
||||||
|
|
||||||
|
/* Add any padding if necessary */
|
||||||
|
if (((*ptr)->alignment - 1) & bytes)
|
||||||
|
bytes = ALIGN(bytes, (*ptr)->alignment);
|
||||||
|
|
||||||
|
bytes += ALIGN((*ptr)->size, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure arg space is aligned to an 8-byte boundary */
|
||||||
|
bytes = ALIGN(bytes, 8);
|
||||||
|
|
||||||
|
/* Make space for the return structure pointer */
|
||||||
|
if (cif->rtype->type == FFI_TYPE_STRUCT) {
|
||||||
|
bytes += sizeof(void*);
|
||||||
|
|
||||||
|
/* Ensure stack is aligned to an 8-byte boundary */
|
||||||
|
bytes = ALIGN(bytes, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
cif->bytes = bytes;
|
||||||
|
|
||||||
|
/* Set the return type flag */
|
||||||
|
switch (cif->rtype->type) {
|
||||||
|
case FFI_TYPE_VOID:
|
||||||
|
case FFI_TYPE_FLOAT:
|
||||||
|
case FFI_TYPE_DOUBLE:
|
||||||
|
cif->flags = (unsigned) cif->rtype->type;
|
||||||
|
break;
|
||||||
|
case FFI_TYPE_SINT64:
|
||||||
|
case FFI_TYPE_UINT64:
|
||||||
|
cif->flags = (unsigned) FFI_TYPE_SINT64;
|
||||||
|
break;
|
||||||
|
case FFI_TYPE_STRUCT:
|
||||||
|
/* Meta can store return values which are <= 64 bits */
|
||||||
|
if (cif->rtype->size <= 4)
|
||||||
|
/* Returned to D0Re0 as 32-bit value */
|
||||||
|
cif->flags = (unsigned)FFI_TYPE_INT;
|
||||||
|
else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8))
|
||||||
|
/* Returned valued is stored to D1Re0|R0Re0 */
|
||||||
|
cif->flags = (unsigned)FFI_TYPE_DOUBLE;
|
||||||
|
else
|
||||||
|
/* value stored in memory */
|
||||||
|
cif->flags = (unsigned)FFI_TYPE_STRUCT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cif->flags = (unsigned)FFI_TYPE_INT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return FFI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exported in API. Entry point
|
||||||
|
* cif -> ffi_cif object
|
||||||
|
* fn -> function pointer
|
||||||
|
* rvalue -> pointer to return value
|
||||||
|
* avalue -> vector of void * pointers pointing to memory locations holding the
|
||||||
|
* arguments
|
||||||
|
*/
|
||||||
|
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||||
|
{
|
||||||
|
extended_cif ecif;
|
||||||
|
|
||||||
|
int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT));
|
||||||
|
ecif.cif = cif;
|
||||||
|
ecif.avalue = avalue;
|
||||||
|
|
||||||
|
double temp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the return value is a struct and we don't have a return value address
|
||||||
|
* then we need to make one
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT))
|
||||||
|
ecif.rvalue = alloca(cif->rtype->size);
|
||||||
|
else if (small_struct)
|
||||||
|
ecif.rvalue = &temp;
|
||||||
|
else
|
||||||
|
ecif.rvalue = rvalue;
|
||||||
|
|
||||||
|
switch (cif->abi) {
|
||||||
|
case FFI_SYSV:
|
||||||
|
ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FFI_ASSERT(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (small_struct)
|
||||||
|
memcpy (rvalue, &temp, cif->rtype->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* private members */
|
||||||
|
|
||||||
|
static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
|
||||||
|
ffi_cif*, float *);
|
||||||
|
|
||||||
|
void ffi_closure_SYSV (ffi_closure *);
|
||||||
|
|
||||||
|
/* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
|
||||||
|
extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */
|
||||||
|
|
||||||
|
/* end of private members */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __tramp: trampoline memory location
|
||||||
|
* __fun: assembly routine
|
||||||
|
* __ctx: memory location for wrapper
|
||||||
|
*
|
||||||
|
* At this point, tramp[0] == __ctx !
|
||||||
|
*/
|
||||||
|
void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) {
|
||||||
|
memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline));
|
||||||
|
*(unsigned int*) &__tramp[40] = __ctx;
|
||||||
|
*(unsigned int*) &__tramp[44] = __fun;
|
||||||
|
/* This will flush the instruction cache */
|
||||||
|
__builtin_meta2_cachewd(&__tramp[0], 1);
|
||||||
|
__builtin_meta2_cachewd(&__tramp[47], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* the cif must already be prepared */
|
||||||
|
|
||||||
|
ffi_status
|
||||||
|
ffi_prep_closure_loc (ffi_closure *closure,
|
||||||
|
ffi_cif* cif,
|
||||||
|
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||||
|
void *user_data,
|
||||||
|
void *codeloc)
|
||||||
|
{
|
||||||
|
void (*closure_func)(ffi_closure*) = NULL;
|
||||||
|
|
||||||
|
if (cif->abi == FFI_SYSV)
|
||||||
|
closure_func = &ffi_closure_SYSV;
|
||||||
|
else
|
||||||
|
return FFI_BAD_ABI;
|
||||||
|
|
||||||
|
ffi_init_trampoline(
|
||||||
|
(unsigned char*)&closure->tramp[0],
|
||||||
|
(unsigned int)closure_func,
|
||||||
|
(unsigned int)codeloc);
|
||||||
|
|
||||||
|
closure->cif = cif;
|
||||||
|
closure->user_data = user_data;
|
||||||
|
closure->fun = fun;
|
||||||
|
|
||||||
|
return FFI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function is jumped to by the trampoline */
|
||||||
|
unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
|
||||||
|
ffi_closure *closure;
|
||||||
|
void **respp;
|
||||||
|
void *args;
|
||||||
|
void *vfp_args;
|
||||||
|
{
|
||||||
|
ffi_cif *cif;
|
||||||
|
void **arg_area;
|
||||||
|
|
||||||
|
cif = closure->cif;
|
||||||
|
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This call will initialize ARG_AREA, such that each
|
||||||
|
* element in that array points to the corresponding
|
||||||
|
* value on the stack; and if the function returns
|
||||||
|
* a structure, it will re-set RESP to point to the
|
||||||
|
* structure return address.
|
||||||
|
*/
|
||||||
|
ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
|
||||||
|
|
||||||
|
(closure->fun) ( cif, *respp, arg_area, closure->user_data);
|
||||||
|
|
||||||
|
return cif->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
|
||||||
|
void **avalue, ffi_cif *cif,
|
||||||
|
float *vfp_stack)
|
||||||
|
{
|
||||||
|
register unsigned int i;
|
||||||
|
register void **p_argv;
|
||||||
|
register char *argp;
|
||||||
|
register ffi_type **p_arg;
|
||||||
|
|
||||||
|
/* stack points to original arguments */
|
||||||
|
argp = stack;
|
||||||
|
|
||||||
|
/* Store return value */
|
||||||
|
if ( cif->flags == FFI_TYPE_STRUCT ) {
|
||||||
|
argp -= 4;
|
||||||
|
*rvalue = *(void **) argp;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_argv = avalue;
|
||||||
|
|
||||||
|
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) {
|
||||||
|
size_t z;
|
||||||
|
size_t alignment;
|
||||||
|
|
||||||
|
alignment = (*p_arg)->alignment;
|
||||||
|
if (alignment < 4)
|
||||||
|
alignment = 4;
|
||||||
|
if ((alignment - 1) & (unsigned)argp)
|
||||||
|
argp = (char *) ALIGN(argp, alignment);
|
||||||
|
|
||||||
|
z = (*p_arg)->size;
|
||||||
|
*p_argv = (void*) argp;
|
||||||
|
p_argv++;
|
||||||
|
argp -= z;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
53
src/metag/ffitarget.h
Normal file
53
src/metag/ffitarget.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* -----------------------------------------------------------------*-C-*-
|
||||||
|
ffitarget.h - Copyright (c) 2013 Imagination Technologies Ltd.
|
||||||
|
Target configuration macros for Meta
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
``Software''), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifndef LIBFFI_TARGET_H
|
||||||
|
#define LIBFFI_TARGET_H
|
||||||
|
|
||||||
|
#ifndef LIBFFI_H
|
||||||
|
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIBFFI_ASM
|
||||||
|
typedef unsigned long ffi_arg;
|
||||||
|
typedef signed long ffi_sarg;
|
||||||
|
|
||||||
|
typedef enum ffi_abi {
|
||||||
|
FFI_FIRST_ABI = 0,
|
||||||
|
FFI_SYSV,
|
||||||
|
FFI_DEFAULT_ABI = FFI_SYSV,
|
||||||
|
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1,
|
||||||
|
} ffi_abi;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
|
#define FFI_CLOSURES 1
|
||||||
|
#define FFI_TRAMPOLINE_SIZE 48
|
||||||
|
#define FFI_NATIVE_RAW_API 0
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
311
src/metag/sysv.S
Normal file
311
src/metag/sysv.S
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
sysv.S - Copyright (c) 2013 Imagination Technologies Ltd.
|
||||||
|
|
||||||
|
Meta Foreign Function Interface
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
``Software''), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define LIBFFI_ASM
|
||||||
|
#include <fficonfig.h>
|
||||||
|
#include <ffi.h>
|
||||||
|
#ifdef HAVE_MACHINE_ASM_H
|
||||||
|
#include <machine/asm.h>
|
||||||
|
#else
|
||||||
|
#ifdef __USER_LABEL_PREFIX__
|
||||||
|
#define CONCAT1(a, b) CONCAT2(a, b)
|
||||||
|
#define CONCAT2(a, b) a ## b
|
||||||
|
|
||||||
|
/* Use the right prefix for global labels. */
|
||||||
|
#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
|
||||||
|
#else
|
||||||
|
#define CNAME(x) x
|
||||||
|
#endif
|
||||||
|
#define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x):
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ELF__
|
||||||
|
#define LSYM(x) .x
|
||||||
|
#else
|
||||||
|
#define LSYM(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.macro call_reg x=
|
||||||
|
.text
|
||||||
|
.balign 4
|
||||||
|
mov D1RtP, \x
|
||||||
|
swap D1RtP, PC
|
||||||
|
.endm
|
||||||
|
|
||||||
|
! Save register arguments
|
||||||
|
.macro SAVE_ARGS
|
||||||
|
.text
|
||||||
|
.balign 4
|
||||||
|
setl [A0StP++], D0Ar6, D1Ar5
|
||||||
|
setl [A0StP++], D0Ar4, D1Ar3
|
||||||
|
setl [A0StP++], D0Ar2, D1Ar1
|
||||||
|
.endm
|
||||||
|
|
||||||
|
! Save retrun, frame pointer and other regs
|
||||||
|
.macro SAVE_REGS regs=
|
||||||
|
.text
|
||||||
|
.balign 4
|
||||||
|
setl [A0StP++], D0FrT, D1RtP
|
||||||
|
! Needs to be a pair of regs
|
||||||
|
.ifnc "\regs",""
|
||||||
|
setl [A0StP++], \regs
|
||||||
|
.endif
|
||||||
|
.endm
|
||||||
|
|
||||||
|
! Declare a global function
|
||||||
|
.macro METAG_FUNC_START name
|
||||||
|
.text
|
||||||
|
.balign 4
|
||||||
|
ENTRY(\name)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
! Return registers from the stack. Reverse SAVE_REGS operation
|
||||||
|
.macro RET_REGS regs=, cond=
|
||||||
|
.ifnc "\regs", ""
|
||||||
|
getl \regs, [--A0StP]
|
||||||
|
.endif
|
||||||
|
getl D0FrT, D1RtP, [--A0StP]
|
||||||
|
.endm
|
||||||
|
|
||||||
|
! Return arguments
|
||||||
|
.macro RET_ARGS
|
||||||
|
getl D0Ar2, D1Ar1, [--A0StP]
|
||||||
|
getl D0Ar4, D1Ar3, [--A0StP]
|
||||||
|
getl D0Ar6, D1Ar5, [--A0StP]
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
! D1Ar1: fn
|
||||||
|
! D0Ar2: &ecif
|
||||||
|
! D1Ar3: cif->bytes
|
||||||
|
! D0Ar4: fig->flags
|
||||||
|
! D1Ar5: ecif.rvalue
|
||||||
|
|
||||||
|
! This assumes we are using GNU as
|
||||||
|
METAG_FUNC_START ffi_call_SYSV
|
||||||
|
! Save argument registers
|
||||||
|
|
||||||
|
SAVE_ARGS
|
||||||
|
|
||||||
|
! new frame
|
||||||
|
mov D0FrT, A0FrP
|
||||||
|
add A0FrP, A0StP, #0
|
||||||
|
|
||||||
|
! Preserve the old frame pointer
|
||||||
|
SAVE_REGS "D1.5, D0.5"
|
||||||
|
|
||||||
|
! Make room for new args. cifs->bytes is the total space for input
|
||||||
|
! and return arguments
|
||||||
|
|
||||||
|
add A0StP, A0StP, D1Ar3
|
||||||
|
|
||||||
|
! Preserve cifs->bytes & fn
|
||||||
|
mov D0.5, D1Ar3
|
||||||
|
mov D1.5, D1Ar1
|
||||||
|
|
||||||
|
! Place all of the ffi_prep_args in position
|
||||||
|
mov D1Ar1, A0StP
|
||||||
|
|
||||||
|
! Call ffi_prep_args(stack, &ecif)
|
||||||
|
#ifdef __PIC__
|
||||||
|
callr D1RtP, CNAME(ffi_prep_args@PLT)
|
||||||
|
#else
|
||||||
|
callr D1RtP, CNAME(ffi_prep_args)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
! Restore fn pointer
|
||||||
|
|
||||||
|
! The foreign stack should look like this
|
||||||
|
! XXXXX XXXXXX <--- stack pointer
|
||||||
|
! FnArgN rvalue
|
||||||
|
! FnArgN+2 FnArgN+1
|
||||||
|
! FnArgN+4 FnArgN+3
|
||||||
|
! ....
|
||||||
|
!
|
||||||
|
|
||||||
|
! A0StP now points to the first (or return) argument + 4
|
||||||
|
|
||||||
|
! Preserve cif->bytes
|
||||||
|
getl D0Ar2, D1Ar1, [--A0StP]
|
||||||
|
getl D0Ar4, D1Ar3, [--A0StP]
|
||||||
|
getl D0Ar6, D1Ar5, [--A0StP]
|
||||||
|
|
||||||
|
! Place A0StP to the first argument again
|
||||||
|
add A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each
|
||||||
|
|
||||||
|
! A0FrP points to the initial stack without the reserved space for the
|
||||||
|
! cifs->bytes, whilst A0StP points to the stack after the space allocation
|
||||||
|
|
||||||
|
! fn was the first argument of ffi_call_SYSV.
|
||||||
|
! The stack at this point looks like this:
|
||||||
|
!
|
||||||
|
! A0StP(on entry to _SYSV) -> Arg6 Arg5 | low
|
||||||
|
! Arg4 Arg3 |
|
||||||
|
! Arg2 Arg1 |
|
||||||
|
! A0FrP ----> D0FrtP D1RtP |
|
||||||
|
! D1.5 D0.5 |
|
||||||
|
! A0StP(bf prep_args) -> FnArgn FnArgn-1 |
|
||||||
|
! FnArgn-2FnArgn-3 |
|
||||||
|
! ................ | <= cifs->bytes
|
||||||
|
! FnArg4 FnArg3 |
|
||||||
|
! A0StP (prv_A0StP+cifs->bytes) FnArg2 FnArg1 | high
|
||||||
|
!
|
||||||
|
! fn was in Arg1 so it's located in in A0FrP+#-0xC
|
||||||
|
!
|
||||||
|
|
||||||
|
! D0Re0 contains the size of arguments stored in registers
|
||||||
|
sub A0StP, A0StP, D0Re0
|
||||||
|
|
||||||
|
! Arg1 is the function pointer for the foreign call. This has been
|
||||||
|
! preserved in D1.5
|
||||||
|
|
||||||
|
! Time to call (fn). Arguments should be like this:
|
||||||
|
! Arg1-Arg6 are loaded to regs
|
||||||
|
! The rest of the arguments are stored in stack pointed by A0StP
|
||||||
|
|
||||||
|
call_reg D1.5
|
||||||
|
|
||||||
|
! Reset stack.
|
||||||
|
|
||||||
|
mov A0StP, A0FrP
|
||||||
|
|
||||||
|
! Load Arg1 with the pointer to storage for the return type
|
||||||
|
! This was stored in Arg5
|
||||||
|
|
||||||
|
getd D1Ar1, [A0FrP+#-20]
|
||||||
|
|
||||||
|
! Load D0Ar2 with the return type code. This was stored in Arg4 (flags)
|
||||||
|
|
||||||
|
getd D0Ar2, [A0FrP+#-16]
|
||||||
|
|
||||||
|
! We are ready to start processing the return value
|
||||||
|
! D0Re0 (and D1Re0) hold the return value
|
||||||
|
|
||||||
|
! If the return value is NULL, assume no return value
|
||||||
|
cmp D1Ar1, #0
|
||||||
|
beq LSYM(Lepilogue)
|
||||||
|
|
||||||
|
! return INT
|
||||||
|
cmp D0Ar2, #FFI_TYPE_INT
|
||||||
|
! Sadly, there is no setd{cc} instruction so we need to workaround that
|
||||||
|
bne .INT64
|
||||||
|
setd [D1Ar1], D0Re0
|
||||||
|
b LSYM(Lepilogue)
|
||||||
|
|
||||||
|
! return INT64
|
||||||
|
.INT64:
|
||||||
|
cmp D0Ar2, #FFI_TYPE_SINT64
|
||||||
|
setleq [D1Ar1], D0Re0, D1Re0
|
||||||
|
|
||||||
|
! return DOUBLE
|
||||||
|
cmp D0Ar2, #FFI_TYPE_DOUBLE
|
||||||
|
setl [D1AR1++], D0Re0, D1Re0
|
||||||
|
|
||||||
|
LSYM(Lepilogue):
|
||||||
|
! At this point, the stack pointer points right after the argument
|
||||||
|
! saved area. We need to restore 4 regs, therefore we need to move
|
||||||
|
! 16 bytes ahead.
|
||||||
|
add A0StP, A0StP, #16
|
||||||
|
RET_REGS "D1.5, D0.5"
|
||||||
|
RET_ARGS
|
||||||
|
getd D0Re0, [A0StP]
|
||||||
|
mov A0FrP, D0FrT
|
||||||
|
swap D1RtP, PC
|
||||||
|
|
||||||
|
.ffi_call_SYSV_end:
|
||||||
|
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
(called by ffi_metag_trampoline)
|
||||||
|
void ffi_closure_SYSV (ffi_closure*)
|
||||||
|
|
||||||
|
(called by ffi_closure_SYSV)
|
||||||
|
unsigned int FFI_HIDDEN
|
||||||
|
ffi_closure_SYSV_inner (closure,respp, args)
|
||||||
|
ffi_closure *closure;
|
||||||
|
void **respp;
|
||||||
|
void *args;
|
||||||
|
*/
|
||||||
|
|
||||||
|
METAG_FUNC_START ffi_closure_SYSV
|
||||||
|
! We assume that D1Ar1 holds the address of the
|
||||||
|
! ffi_closure struct. We will use that to fetch the
|
||||||
|
! arguments. The stack pointer points to an empty space
|
||||||
|
! and it is ready to store more data.
|
||||||
|
|
||||||
|
! D1Ar1 is ready
|
||||||
|
! Allocate stack space for return value
|
||||||
|
add A0StP, A0StP, #8
|
||||||
|
! Store it to D0Ar2
|
||||||
|
sub D0Ar2, A0StP, #8
|
||||||
|
|
||||||
|
sub D1Ar3, A0FrP, #4
|
||||||
|
|
||||||
|
! D1Ar3 contains the address of the original D1Ar1 argument
|
||||||
|
! We need to subtract #4 later on
|
||||||
|
|
||||||
|
! Preverve D0Ar2
|
||||||
|
mov D0.5, D0Ar2
|
||||||
|
|
||||||
|
#ifdef __PIC__
|
||||||
|
callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT)
|
||||||
|
#else
|
||||||
|
callr D1RtP, CNAME(ffi_closure_SYSV_inner)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
! Check the return value and store it to D0.5
|
||||||
|
cmp D0Re0, #FFI_TYPE_INT
|
||||||
|
beq .Lretint
|
||||||
|
cmp D0Re0, #FFI_TYPE_DOUBLE
|
||||||
|
beq .Lretdouble
|
||||||
|
.Lclosure_epilogue:
|
||||||
|
sub A0StP, A0StP, #8
|
||||||
|
RET_REGS "D1.5, D0.5"
|
||||||
|
RET_ARGS
|
||||||
|
swap D1RtP, PC
|
||||||
|
|
||||||
|
.Lretint:
|
||||||
|
setd [D0.5], D0Re0
|
||||||
|
b .Lclosure_epilogue
|
||||||
|
.Lretdouble:
|
||||||
|
setl [D0.5++], D0Re0, D1Re0
|
||||||
|
b .Lclosure_epilogue
|
||||||
|
.ffi_closure_SYSV_end:
|
||||||
|
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
|
||||||
|
|
||||||
|
|
||||||
|
ENTRY(ffi_metag_trampoline)
|
||||||
|
SAVE_ARGS
|
||||||
|
! New frame
|
||||||
|
mov A0FrP, A0StP
|
||||||
|
SAVE_REGS "D1.5, D0.5"
|
||||||
|
mov D0.5, PC
|
||||||
|
! Load D1Ar1 the value of ffi_metag_trampoline
|
||||||
|
getd D1Ar1, [D0.5 + #8]
|
||||||
|
! Jump to ffi_closure_SYSV
|
||||||
|
getd PC, [D0.5 + #12]
|
||||||
Reference in New Issue
Block a user