Add Meta processor support
This commit is contained in:
@@ -2,6 +2,15 @@
|
||||
|
||||
* 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>
|
||||
|
||||
* 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/tile/ffitarget.h src/tile/tile.S libtool-version \
|
||||
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 \
|
||||
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \
|
||||
m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \
|
||||
@@ -208,6 +209,9 @@ endif
|
||||
if XTENSA
|
||||
nodist_libffi_la_SOURCES += src/xtensa/sysv.S src/xtensa/ffi.c
|
||||
endif
|
||||
if METAG
|
||||
nodist_libffi_la_SOURCES += src/metag/sysv.S src/metag/ffi.c
|
||||
endif
|
||||
|
||||
libffi_convenience_la_SOURCES = $(libffi_la_SOURCES)
|
||||
nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
|
||||
|
||||
8
README
8
README
@@ -1,7 +1,7 @@
|
||||
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/>.
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ tested:
|
||||
| M68K | FreeMiNT | GCC |
|
||||
| M68K | Linux | GCC |
|
||||
| M68K | RTEMS | GCC |
|
||||
| Meta | Linux | GCC |
|
||||
| MicroBlaze | Linux | GCC |
|
||||
| MIPS | IRIX | GCC |
|
||||
| MIPS | Linux | GCC |
|
||||
@@ -162,6 +163,11 @@ History
|
||||
|
||||
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
|
||||
Add Moxie support.
|
||||
Add AArch64 support.
|
||||
|
||||
@@ -199,6 +199,10 @@ case "$host" in
|
||||
TARGET=MOXIE; TARGETDIR=moxie
|
||||
;;
|
||||
|
||||
metag-*-*)
|
||||
TARGET=METAG; TARGETDIR=metag
|
||||
;;
|
||||
|
||||
mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
|
||||
TARGET=MIPS; TARGETDIR=mips
|
||||
;;
|
||||
@@ -278,6 +282,7 @@ AM_CONDITIONAL(IA64, test x$TARGET = xIA64)
|
||||
AM_CONDITIONAL(M32R, test x$TARGET = xM32R)
|
||||
AM_CONDITIONAL(M68K, test x$TARGET = xM68K)
|
||||
AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
|
||||
AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
|
||||
AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
|
||||
AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
|
||||
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