Many many updates. Merge from gcc and then some.

This commit is contained in:
green
2001-04-09 00:58:38 +00:00
parent f7e9f91ade
commit 8807355af3
42 changed files with 4394 additions and 1157 deletions

View File

@@ -27,6 +27,7 @@ TARGET_SRC_ALPHA = alpha/ffi.c alpha/osf.S
TARGET_SRC_M68K = m68k/ffi.c m68k/sysv.S
TARGET_SRC_POWERPC = powerpc/ffi.c powerpc/sysv.S
TARGET_SRC_ARM = arm/sysv.S arm/ffi.c
TARGET_SRC_S390 = s390/sysv.S s390/ffi.c
##libffi_la_SOURCES = debug.c prep_cif.c types.c $(TARGET_SRC_@TARGET@)
## Work around automake deficiency

View File

@@ -3,8 +3,6 @@
Alpha Foreign Function Interface
$Id: ffi.c,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -30,131 +28,25 @@
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
extern void ffi_closure_osf(void);
static void
ffi_prep_args(char *stack, extended_cif *ecif, int bytes, int flags)
{
register long i, avn;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
/* To streamline things in the assembly code, we always allocate 12
words for loading up the int and fp argument registers. The layout
is as when processing varargs: the 6 fp args, the 6 int args, then
the incoming stack. ARGP points to the first int slot. */
argp = stack + 6 * SIZEOF_ARG;
memset (stack, 0, 12 * SIZEOF_ARG);
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
{
*(void **) argp = ecif->rvalue;
argp += sizeof(void *);
}
i = 0;
avn = ecif->cif->nargs;
p_arg = ecif->cif->arg_types;
p_argv = ecif->avalue;
while (i < avn)
{
size_t z = ALIGN((*p_arg)->size, SIZEOF_ARG);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(SINT64 *) argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(UINT64 *) argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(SINT64 *) argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(UINT64 *) argp = *(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(SINT64 *) argp = *(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(UINT64 *) argp = *(UINT32 *)(* p_argv);
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
*(UINT64 *) argp = *(UINT64 *)(* p_argv);
break;
case FFI_TYPE_FLOAT:
if (argp - stack < 12 * SIZEOF_ARG)
{
/* Note the conversion -- all the fp regs are loaded as
doubles. The in-register format is the same. */
*(double *) (argp - 6 * SIZEOF_ARG) = *(float *)(* p_argv);
}
else
*(float *) argp = *(float *)(* p_argv);
break;
case FFI_TYPE_DOUBLE:
if (argp - stack < 12 * SIZEOF_ARG)
*(double *) (argp - 6 * SIZEOF_ARG) = *(double *)(* p_argv);
else
*(double *) argp = *(double *)(* p_argv);
break;
case FFI_TYPE_STRUCT:
memcpy(argp, *p_argv, (*p_arg)->size);
break;
default:
FFI_ASSERT(0);
}
argp += z;
i++, p_arg++, p_argv++;
}
}
/* Perform machine dependent cif processing */
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Adjust cif->bytes. to include 12 words for the temporary register
argument loading area. This will be removed before the call. */
cif->bytes += 6*SIZEOF_ARG;
if (cif->bytes < 12*SIZEOF_ARG)
cif->bytes = 12*SIZEOF_ARG;
/* The stack must be double word aligned, so round bytes up
appropriately. */
cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
/* Adjust cif->bytes to represent a minimum 6 words for the temporary
register argument loading area. */
if (cif->bytes < 6*SIZEOF_ARG)
cif->bytes = 6*SIZEOF_ARG;
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
cif->flags = cif->rtype->type;
break;
case FFI_TYPE_FLOAT:
cif->flags = FFI_TYPE_FLOAT;
break;
case FFI_TYPE_DOUBLE:
cif->flags = FFI_TYPE_DOUBLE;
cif->flags = cif->rtype->type;
break;
default:
@@ -165,35 +57,191 @@ ffi_prep_cif_machdep(ffi_cif *cif)
return FFI_OK;
}
extern int ffi_call_osf(void (*)(char *, extended_cif *, int, int),
extended_cif *, unsigned,
unsigned, unsigned *, void (*)());
void
ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
unsigned long *stack, *argp;
long i, avn;
ffi_type **arg_types;
FFI_ASSERT (cif->abi == FFI_OSF);
/* 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->rtype->type == FFI_TYPE_STRUCT)
ecif.rvalue = alloca(cif->rtype->size);
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
case FFI_OSF:
ffi_call_osf(ffi_prep_args, &ecif, cif->bytes,
cif->flags, rvalue, fn);
break;
if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT)
rvalue = alloca(cif->rtype->size);
default:
FFI_ASSERT(0);
break;
/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
argp = stack = alloca(cif->bytes + 4*SIZEOF_ARG);
if (cif->flags == FFI_TYPE_STRUCT)
*(void **) argp++ = rvalue;
i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
while (i < avn)
{
switch ((*arg_types)->type)
{
case FFI_TYPE_SINT8:
*(SINT64 *) argp = *(SINT8 *)(* avalue);
break;
case FFI_TYPE_UINT8:
*(SINT64 *) argp = *(UINT8 *)(* avalue);
break;
case FFI_TYPE_SINT16:
*(SINT64 *) argp = *(SINT16 *)(* avalue);
break;
case FFI_TYPE_UINT16:
*(SINT64 *) argp = *(UINT16 *)(* avalue);
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
/* Note that unsigned 32-bit quantities are sign extended. */
*(SINT64 *) argp = *(SINT32 *)(* avalue);
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
*(UINT64 *) argp = *(UINT64 *)(* avalue);
break;
case FFI_TYPE_FLOAT:
if (argp - stack < 6)
{
/* Note the conversion -- all the fp regs are loaded as
doubles. The in-register format is the same. */
*(double *) argp = *(float *)(* avalue);
}
else
*(float *) argp = *(float *)(* avalue);
break;
case FFI_TYPE_DOUBLE:
*(double *) argp = *(double *)(* avalue);
break;
case FFI_TYPE_STRUCT:
memcpy(argp, *avalue, (*arg_types)->size);
break;
default:
FFI_ASSERT(0);
}
argp += ALIGN((*arg_types)->size, SIZEOF_ARG) / SIZEOF_ARG;
i++, arg_types++, avalue++;
}
ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
}
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
unsigned int *tramp;
FFI_ASSERT (cif->abi == FFI_OSF);
tramp = (unsigned int *) &closure->tramp[0];
tramp[0] = 0x47fb0401; /* mov $27,$1 */
tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
tramp[3] = 0x47ff041f; /* nop */
*(void **) &tramp[4] = ffi_closure_osf;
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* Flush the Icache. */
asm volatile ("imb" : : : "memory");
return FFI_OK;
}
int
ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
{
ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
long i, avn, argn;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
argn = 0;
/* Copy the caller's structure return address to that the closure
returns the data directly to the caller. */
if (cif->flags == FFI_TYPE_STRUCT)
{
rvalue = (void *) argp[0];
argn = 1;
}
i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
/* Grab the addresses of the arguments from the stack frame. */
while (i < avn)
{
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
case FFI_TYPE_STRUCT:
avalue[i] = &argp[argn];
break;
case FFI_TYPE_FLOAT:
if (argn < 6)
{
/* Floats coming from registers need conversion from double
back to float format. */
*(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
avalue[i] = &argp[argn - 6];
}
else
avalue[i] = &argp[argn];
break;
case FFI_TYPE_DOUBLE:
avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
break;
default:
FFI_ASSERT(0);
}
argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
i++;
}
/* Invoke the closure. */
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_osf how to perform return type promotions. */
return cif->rtype->type;
}

View File

@@ -3,8 +3,6 @@
Alpha/OSF Foreign Function Interface
$Id: osf.S,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -28,91 +26,252 @@
#define LIBFFI_ASM
#include <ffi.h>
#define callback $16
#define ecifp $17
#define bytes $18
#define flags $19
#define raddr $20
#define fn $21
#define flags_ofs 16
#define raddr_ofs 24
#define fn_ofs 32
#define SIZEOF_FRAME (6*8)
.arch ev6
.text
.align 4
/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
void *raddr, void (*fnaddr)());
Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */
.align 3
.globl ffi_call_osf
.ent ffi_call_osf
ffi_call_osf:
lda $30, -SIZEOF_FRAME($30)
stq $26, 0($30)
stq $15, 8($30)
stq flags, flags_ofs($30)
stq raddr, raddr_ofs($30)
stq fn, fn_ofs($30)
mov $30, $15
.frame $15, SIZEOF_FRAME, $26, 0
.mask 0x4008000, -SIZEOF_FRAME
.frame $15, 32, $26, 0
.mask 0x4008000, -32
addq $16,$17,$1
mov $16, $30
stq $26, 0($1)
stq $15, 8($1)
stq $18, 16($1)
mov $1, $15
.prologue 0
mov callback, $27 # mov callback into place
subq $30, bytes, $30 # allocate stack space
# Call ffi_prep_args; ecif, bytes and flags are already in place.
mov $30, $16 # push stack arg
jsr $26, ($27), 0
stq $19, 24($1)
mov $20, $27
# Load up all of the (potential) argument registers.
ldq $16, 0($30)
ldt $f16, 0($30)
ldt $f17, 8($30)
ldq $17, 8($30)
ldt $f18, 16($30)
ldq $18, 16($30)
ldt $f19, 24($30)
ldq $19, 24($30)
ldt $f20, 32($30)
ldq $20, 32($30)
ldt $f21, 40($30)
ldq $16, 48($30)
ldq $17, 56($30)
ldq $18, 64($30)
ldq $19, 72($30)
ldq $20, 80($30)
ldq $21, 88($30)
ldq $21, 40($30)
# Deallocate the register argument area.
lda $30, 48($30)
# Get rid of the arg reg temp space and call the function.
ldq $27, fn_ofs($15)
lda $30, 12*8($30)
jsr $26, ($27), 0
ldgp $29, 0($26)
# If the return value pointer is NULL, assume no return value.
ldq raddr, raddr_ofs($15)
beq raddr, $noretval
ldq flags, flags_ofs($15)
cmpeq flags, FFI_TYPE_INT, $1
bne $1, $retint
cmpeq flags, FFI_TYPE_FLOAT, $2
bne $2, $retfloat
cmpeq flags, FFI_TYPE_DOUBLE, $3
bne $3, $retdouble
br $retstruct
.align 3
$retint:
stq $0, 0(raddr)
br $noretval
$retfloat:
sts $f0, 0(raddr)
br $noretval
$retdouble:
stt $f0, 0(raddr)
$retstruct:
$noretval:
mov $15, $30
ldq $19, 24($15)
ldq $18, 16($15)
ldq $26, 0($15)
beq $19, $noretval
# Store the return value out in the proper type.
cmpeq $18, FFI_TYPE_INT, $1
bne $1, $retint
cmpeq $18, FFI_TYPE_FLOAT, $2
bne $2, $retfloat
cmpeq $18, FFI_TYPE_DOUBLE, $3
bne $3, $retdouble
$noretval:
ldq $15, 8($15)
ret
$retint:
stq $0, 0($19)
nop
ldq $15, 8($15)
ret
$retfloat:
sts $f0, 0($19)
nop
ldq $15, 8($15)
ret
$retdouble:
stt $f0, 0($19)
nop
ldq $15, 8($15)
lda $30, SIZEOF_FRAME($30)
ret
.end ffi_call_osf
/* ffi_closure_osf(...)
Receives the closure argument in $1. */
.align 3
.globl ffi_closure_osf
.ent ffi_closure_osf
ffi_closure_osf:
.frame $30, 16*8, $26, 0
.mask 0x4000000, -16*8
ldgp $29, 0($27)
subq $30, 16*8, $30
stq $26, 0($30)
.prologue 1
# Store all of the potential argument registers in va_list format.
stt $f16, 4*8($30)
stt $f17, 5*8($30)
stt $f18, 6*8($30)
stt $f19, 7*8($30)
stt $f20, 8*8($30)
stt $f21, 9*8($30)
stq $16, 10*8($30)
stq $17, 11*8($30)
stq $18, 12*8($30)
stq $19, 13*8($30)
stq $20, 14*8($30)
stq $21, 15*8($30)
# Call ffi_closure_osf_inner to do the bulk of the work.
mov $1, $16
lda $17, 2*8($30)
lda $18, 10*8($30)
jsr $26, ffi_closure_osf_inner
ldgp $29, 0($26)
ldq $26, 0($30)
# Load up the return value in the proper type.
lda $1, $load_table
s4addq $0, $1, $1
ldl $1, 0($1)
addq $1, $29, $1
jmp $31, ($1), $load_32
.align 4
$load_none:
addq $30, 16*8, $30
ret
.align 4
$load_float:
lds $f0, 16($30)
nop
addq $30, 16*8, $30
ret
.align 4
$load_double:
ldt $f0, 16($30)
nop
addq $30, 16*8, $30
ret
.align 4
$load_u8:
#ifdef __alpha_bwx__
ldbu $0, 16($30)
nop
#else
ldq $0, 16($30)
and $0, 255, $0
#endif
addq $30, 16*8, $30
ret
.align 4
$load_s8:
#ifdef __alpha_bwx__
ldbu $0, 16($30)
sextb $0, $0
#else
ldq $0, 16($30)
sll $0, 56, $0
sra $0, 56, $0
#endif
addq $30, 16*8, $30
ret
.align 4
$load_u16:
#ifdef __alpha_bwx__
ldwu $0, 16($30)
nop
#else
ldq $0, 16($30)
zapnot $0, 3, $0
#endif
addq $30, 16*8, $30
ret
.align 4
$load_s16:
#ifdef __alpha_bwx__
ldwu $0, 16($30)
sextw $0, $0
#else
ldq $0, 16($30)
sll $0, 48, $0
sra $0, 48, $0
#endif
addq $30, 16*8, $30
ret
.align 4
$load_32:
ldl $0, 16($30)
nop
addq $30, 16*8, $30
ret
.align 4
$load_64:
ldq $0, 16($30)
nop
addq $30, 16*8, $30
ret
.end ffi_closure_osf
.section .rodata
$load_table:
.gprel32 $load_none # FFI_TYPE_VOID
.gprel32 $load_32 # FFI_TYPE_INT
.gprel32 $load_float # FFI_TYPE_FLOAT
.gprel32 $load_double # FFI_TYPE_DOUBLE
.gprel32 $load_double # FFI_TYPE_LONGDOUBLE
.gprel32 $load_u8 # FFI_TYPE_UINT8
.gprel32 $load_s8 # FFI_TYPE_SINT8
.gprel32 $load_u16 # FFI_TYPE_UINT16
.gprel32 $load_s16 # FFI_TYPE_SINT16
.gprel32 $load_32 # FFI_TYPE_UINT32
.gprel32 $load_32 # FFI_TYPE_SINT32
.gprel32 $load_64 # FFI_TYPE_UINT64
.gprel32 $load_64 # FFI_TYPE_SINT64
.gprel32 $load_none # FFI_TYPE_STRUCT
.gprel32 $load_64 # FFI_TYPE_POINTER
/* Assert that the table above is in sync with ffi.h. */
#if FFI_TYPE_FLOAT != 2 \
|| FFI_TYPE_DOUBLE != 3 \
|| FFI_TYPE_UINT8 != 5 \
|| FFI_TYPE_SINT8 != 6 \
|| FFI_TYPE_UINT16 != 7 \
|| FFI_TYPE_SINT16 != 8 \
|| FFI_TYPE_UINT32 != 9 \
|| FFI_TYPE_SINT32 != 10 \
|| FFI_TYPE_UINT64 != 11 \
|| FFI_TYPE_SINT64 != 12 \
|| FFI_TYPE_STRUCT != 13 \
|| FFI_TYPE_POINTER != 14 \
|| FFI_TYPE_LAST != 14
#error "osf.S out of sync with ffi.h"
#endif

View File

@@ -3,8 +3,6 @@
ARM Foreign Function Interface
$Id: ffi.c,v 1.1 1998/11/29 16:48:16 green Exp $
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

View File

@@ -3,8 +3,6 @@
ARM Foreign Function Interface
$Id: sysv.S,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -97,19 +95,13 @@ ENTRY(ffi_call_SYSV)
beq epilogue
# return FLOAT
cmp a4, #FFI_TYPE_FLOAT
bne retdouble
stfs f0, [a3]
b epilogue
cmp a4, #FFI_TYPE_FLOAT
stfeqs f0, [a3]
beq epilogue
# return DOUBLE or LONGDOUBLE
retdouble:
cmp a4, #FFI_TYPE_DOUBLE
bne epilogue
stfs f0, [a3, #0]
stfs f1, [a3, #4]
b epilogue
cmp a4, #FFI_TYPE_DOUBLE
stfeqd f0, [a3]
epilogue:
ldmfd sp!, {a1-a4, fp, pc}

View File

@@ -1,7 +1,5 @@
/* -----------------------------------------------------------------------
debug.c - Copyright (c) 1996 Cygnus Solutions
$Id: debug.c,v 1.1 1998/11/29 16:48:16 green Exp $
debug.c - Copyright (c) 1996 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -17,7 +15,7 @@
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
IN NO EVENT SHALL RED HAT 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.

View File

@@ -1,8 +1,6 @@
/* -----------------------------------------------------------------------
ffitest.c - Copyright (c) 1996, 1997, 1998 Cygnus Solutions
$Id: ffitest.c,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -17,7 +15,7 @@
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
IN NO EVENT SHALL RED HAT 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.
@@ -196,6 +194,16 @@ static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2)
return ts1;
}
/* Take an int and a float argument, together with int userdata, and */
/* return the sum. */
static void closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
{
*(int*)resp =
*(int *)args[0] + (int)(*(float *)args[1]) + (int)(long)userdata;
}
typedef int (*closure_test_type)(int, float);
int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
{
ffi_cif cif;
@@ -214,7 +222,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
signed int si1;
signed int si2;
#if defined(ALPHA) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
#if defined(ALPHA) || defined(IA64) || defined(SPARC64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
long long rint;
#else
int rint;
@@ -285,7 +293,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
/* return value tests */
{
#if defined(MIPS) || defined(SPARC) /* || defined(ARM) */
#if defined(MIPS) /* || defined(ARM) */
puts ("long long tests not run. This is a known bug on this architecture.");
#else
args[0] = &ffi_type_sint64;
@@ -533,6 +541,8 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
printf("%lu promotion tests run\n", ul);
}
#ifndef X86_WIN32 /* Structures dont work on Win32 */
/* struct tests */
{
test_structure_1 ts1_arg;
@@ -691,6 +701,31 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
free (ts5_result);
}
#else
printf("Structure passing doesn't work on Win32.\n");
#endif /* X86_WIN32 */
# if FFI_CLOSURES
/* A simple closure test */
{
ffi_closure cl;
ffi_type * cl_arg_types[3];
cl_arg_types[0] = &ffi_type_sint;
cl_arg_types[1] = &ffi_type_float;
cl_arg_types[2] = NULL;
/* Initialize the cif */
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2,
&ffi_type_sint, cl_arg_types) == FFI_OK);
CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn,
(void *) 3 /* userdata */)
== FFI_OK);
CHECK((*((closure_test_type)(&cl)))(1, 2.0) == 6);
}
# endif
/* If we arrived here, all is good */
(void) puts("\nLooks good. No surprises.\n");

View File

@@ -22,7 +22,7 @@
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
IN NO EVENT SHALL RED HAT 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.

View File

@@ -3,8 +3,6 @@
MIPS Foreign Function Interface
$Id: ffi.c,v 1.1 1998/11/29 16:48:16 green Exp $
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

View File

@@ -3,8 +3,6 @@
MIPS Foreign Function Interface
$Id: n32.S,v 1.1 1998/11/29 16:48:16 green Exp $
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

View File

@@ -3,8 +3,6 @@
MIPS Foreign Function Interface
$Id: o32.S,v 1.1 1998/11/29 16:48:16 green Exp $
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

View File

@@ -3,7 +3,7 @@
PowerPC Foreign Function Interface
$Id: ffi.c,v 1.1 1998/11/29 16:48:16 green Exp $
$Id: ffi.c,v 1.2 2001/04/09 00:58:37 green Exp $
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -29,6 +29,9 @@
#include <ffi_common.h>
#include <stdlib.h>
#include <stdio.h>
extern void ffi_closure_SYSV(void);
enum {
/* The assembly depends on these exact flags. */
@@ -172,6 +175,18 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
}
else
{
/* whoops: abi states only certain register pairs
* can be used for passing long long int
* specifically (r3,r4), (r5,r6), (r7,r8),
* (r9,r10) and if next arg is long long but
* not correct starting register of pair then skip
* until the proper starting register
*/
if (intarg_count%2 != 0)
{
intarg_count ++;
gpr_base++;
}
*(long long *)gpr_base = *(long long *)*p_argv;
gpr_base += 2;
}
@@ -421,3 +436,245 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
break;
}
}
static void flush_icache(char *, int);
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
unsigned int *tramp;
FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
tramp = (unsigned int *) &closure->tramp[0];
tramp[0] = 0x7c0802a6; /* mflr r0 */
tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */
tramp[4] = 0x7d6802a6; /* mflr r11 */
tramp[5] = 0x7c0803a6; /* mtlr r0 */
tramp[6] = 0x800b0000; /* lwz r0,0(r11) */
tramp[7] = 0x816b0004; /* lwz r11,4(r11) */
tramp[8] = 0x7c0903a6; /* mtctr r0 */
tramp[9] = 0x4e800420; /* bctr */
*(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */
*(void **) &tramp[3] = (void *)closure; /* context */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* Flush the icache. */
flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
return FFI_OK;
}
#define MIN_CACHE_LINE_SIZE 8
static void flush_icache(char * addr1, int size)
{
int i;
char * addr;
for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
addr = addr1 + i;
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
}
addr = addr1 + size - 1;
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
}
int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*,
unsigned long*, unsigned long*);
/* Basically the trampoline invokes ffi_closure_SYSV, and on
* entry, r11 holds the address of the closure.
* After storing the registers that could possibly contain
* parameters to be passed into the stack frame and setting
* up space for a return value, ffi_closure_SYSV invokes the
* following helper function to do most of the work
*/
int
ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
unsigned long * pgr, unsigned long * pfr,
unsigned long * pst)
{
/* rvalue is the pointer to space for return value in closure assembly */
/* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */
/* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */
/* pst is the pointer to outgoing parameter stack in original caller */
void ** avalue;
ffi_type ** arg_types;
long i, avn;
long nf; /* number of floating registers already used */
long ng; /* number of general registers already used */
ffi_cif * cif;
double temp;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
nf = 0;
ng = 0;
/* Copy the caller's structure return value address so that the closure
returns the data directly to the caller. */
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
rvalue = *pgr;
ng++;
pgr++;
}
i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
/* Grab the addresses of the arguments from the stack frame. */
while (i < avn)
{
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
/* there are 8 gpr registers used to pass values */
if (ng < 8) {
avalue[i] = (((char *)pgr)+3);
ng++;
pgr++;
} else {
avalue[i] = (((char *)pst)+3);
pst++;
}
break;
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
/* there are 8 gpr registers used to pass values */
if (ng < 8) {
avalue[i] = (((char *)pgr)+2);
ng++;
pgr++;
} else {
avalue[i] = (((char *)pst)+2);
pst++;
}
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER:
case FFI_TYPE_STRUCT:
/* there are 8 gpr registers used to pass values */
if (ng < 8) {
avalue[i] = pgr;
ng++;
pgr++;
} else {
avalue[i] = pst;
pst++;
}
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
/* passing long long ints are complex, they must
* be passed in suitable register pairs such as
* (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
* and if the entire pair aren't available then the outgoing
* parameter stack is used for both but an alignment of 8
* must will be kept. So we must either look in pgr
* or pst to find the correct address for this type
* of parameter.
*/
if (ng < 7) {
if (ng & 0x01) {
/* skip r4, r6, r8 as starting points */
ng++;
pgr++;
}
avalue[i] = pgr;
ng+=2;
pgr+=2;
} else {
if (((long)pst) & 4) pst++;
avalue[i] = pst;
pst+=2;
}
break;
case FFI_TYPE_FLOAT:
/* unfortunately float values are stored as doubles
* in the ffi_closure_SYSV code (since we don't check
* the type in that routine). This is also true
* of floats passed on the outgoing parameter stack.
* Also, on the outgoing stack all values are aligned
* to 8
*
* Don't you just love the simplicity of this ABI!
*/
/* there are 8 64bit floating point registers */
if (nf < 8) {
temp = *(double*)pfr;
*(float*)pfr = (float)temp;
avalue[i] = pfr;
nf++;
pfr+=2;
} else {
/* FIXME? here we are really changing the values
* stored in the original calling routines outgoing
* parameter stack. This is probably a really
* naughty thing to do but...
*/
if (((long)pst) & 4) pst++;
temp = *(double*)pst;
*(float*)pst = (float)temp;
avalue[i] = pst;
nf++;
pst+=2;
}
break;
case FFI_TYPE_DOUBLE:
/* On the outgoing stack all values are aligned to 8 */
/* there are 8 64bit floating point registers */
if (nf < 8) {
avalue[i] = pfr;
nf++;
pfr+=2;
} else {
if (((long)pst) & 4) pst++;
avalue[i] = pst;
nf++;
pst+=2;
}
break;
default:
FFI_ASSERT(0);
}
i++;
}
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_osf how to perform return type promotions. */
return cif->rtype->type;
}

View File

@@ -0,0 +1,148 @@
#define LIBFFI_ASM
#include <powerpc/asm.h>
.globl ffi_closure_helper_SYSV
ENTRY(ffi_closure_SYSV)
stwu %r1,-144(%r1)
mflr %r0
stw %r31,140(%r1)
stw %r0,148(%r1)
# we want to build up an areas for the parameters passed
# in registers (both floating point and integer)
# so first save gpr 3 to gpr 10 (aligned to 4)
stw %r3, 16(%r1)
stw %r4, 20(%r1)
stw %r5, 24(%r1)
stw %r6, 28(%r1)
stw %r7, 32(%r1)
stw %r8, 36(%r1)
stw %r9, 40(%r1)
stw %r10,44(%r1)
# next save fpr 1 to fpr 8 (aligned to 8)
stfd %f1, 48(%r1)
stfd %f2, 56(%r1)
stfd %f3, 64(%r1)
stfd %f4, 72(%r1)
stfd %f5, 80(%r1)
stfd %f6, 88(%r1)
stfd %f7, 96(%r1)
stfd %f8, 104(%r1)
# set up registers for the routine that actually does the work
# get the context pointer from the trampoline
mr %r3,%r11
# now load up the pointer to the result storage
addi %r4,%r1,112
# now load up the pointer to the saved gpr registers
addi %r5,%r1,16
# now load up the pointer to the saved fpr registers */
addi %r6,%r1,48
# now load up the pointer to the outgoing parameter
# stack in the previous frame
# i.e. the previous frame pointer + 8
addi %r7,%r1,152
# make the call
bl JUMPTARGET(ffi_closure_helper_SYSV)
# now r3 contains the return type
# so use it to look up in a table
# so we know how to deal with each type
# look up the proper starting point in table
# by using return type as offset
addi %r5,%r1,112 # get pointer to results area
addis %r4,0,.L60@ha # get address of jump table
addi %r4,%r4,.L60@l
slwi %r3,%r3,2 # now multiply return type by 4
lwzx %r3,%r4,%r3 # get the contents of that table value
add %r3,%r3,%r4 # add contents of table to table address
mtctr %r3
bctr # jump to it
.align 2
.L60:
.long .L44-.L60 # FFI_TYPE_VOID
.long .L50-.L60 # FFI_TYPE_INT
.long .L47-.L60 # FFI_TYPE_FLOAT
.long .L46-.L60 # FFI_TYPE_DOUBLE
.long .L46-.L60 # FFI_TYPE_LONGDOUBLE
.long .L56-.L60 # FFI_TYPE_UINT8
.long .L55-.L60 # FFI_TYPE_SINT8
.long .L58-.L60 # FFI_TYPE_UINT16
.long .L57-.L60 # FFI_TYPE_SINT16
.long .L50-.L60 # FFI_TYPE_UINT32
.long .L50-.L60 # FFI_TYPE_SINT32
.long .L48-.L60 # FFI_TYPE_UINT64
.long .L48-.L60 # FFI_TYPE_SINT64
.long .L44-.L60 # FFI_TYPE_STRUCT
.long .L50-.L60 # FFI_TYPE_POINTER
# case double
.L46:
lfd %f1,0(%r5)
b .L44
# case float
.L47:
lfs %f1,0(%r5)
b .L44
# case long long
.L48:
lwz %r3,0(%r5)
lwz %r4,4(%r5)
b .L44
# case default / int32 / pointer
.L50:
lwz %r3,0(%r5)
b .L44
# case signed int8
.L55:
addi %r5,%r5,3
lbz %r3,0(%r5)
extsb %r3,%r3
b .L44
# case unsigned int8
.L56:
addi %r5,%r5,3
lbz %r3,0(%r5)
b .L44
# case signed int16
.L57:
addi %r5,%r5,2
lhz %r3,0(%r5)
extsh %r3,%r3
b .L44
#case unsigned int16
.L58:
addi %r5,%r5,2
lhz %r3,0(%r5)
# case void / done
.L44:
lwz %r11,0(%r1)
lwz %r0,4(%r11)
mtlr %r0
lwz %r31,-4(%r11)
mr %r1,%r11
blr
END(ffi_closure_SYSV)

View File

@@ -1,8 +1,6 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 1996, 1998 Cygnus Solutions
$Id: prep_cif.c,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -17,7 +15,7 @@
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
IN NO EVENT SHALL RED HAT 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.
@@ -107,7 +105,11 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
#ifndef M68K
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT)
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
#endif
)
bytes = STACK_ARG_SIZE(sizeof(void*));
#endif
@@ -121,8 +123,10 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
return FFI_BAD_TYPEDEF;
#ifdef SPARC
if ((*ptr)->type == FFI_TYPE_STRUCT
|| (*ptr)->type == FFI_TYPE_LONGDOUBLE)
if (((*ptr)->type == FFI_TYPE_STRUCT
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
|| ((*ptr)->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_V9))
bytes += sizeof(void*);
else
#endif
@@ -140,4 +144,3 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
/* Perform machine dependent cif processing */
return ffi_prep_cif_machdep(cif);
}

View File

@@ -19,7 +19,7 @@
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
IN NO EVENT SHALL RED HAT 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.
@@ -202,13 +202,13 @@ void ffi_raw_call (/*@dependent@*/ ffi_cif *cif,
#if FFI_CLOSURES /* base system provides closures */
static void
ffi_translate_args (ffi_cif *cif, void *ravlue,
ffi_translate_args (ffi_cif *cif, void *rvalue,
void **avalue, void *user_data)
{
ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
ffi_ptrarray_to_raw (cif, avalue, raw);
ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
ffi_ptrarray_to_raw (cif, avalue, raw);
(*cl->fun) (cif, rvalue, raw, cl->user_data);
}
@@ -226,7 +226,7 @@ ffi_prep_raw_closure (ffi_raw_closure* cl,
status = ffi_prep_closure ((ffi_closure*) cl,
cif,
&ffi_closure_translate,
&ffi_translate_args,
(void*)cl);
if (status == FFI_OK)
{

589
libffi/src/s390/ffi.c Normal file
View File

@@ -0,0 +1,589 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2000 Software AG
S390 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 AUTHOR 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.
----------------------------------------------------------------------- */
/*====================================================================*/
/* Includes */
/* -------- */
/*====================================================================*/
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <stdio.h>
/*====================== End of Includes =============================*/
/*====================================================================*/
/* Defines */
/* ------- */
/*====================================================================*/
#define MAX_GPRARGS 5 /* Max. no. of GPR available */
#define MAX_FPRARGS 2 /* Max. no. of FPR available */
#define STR_GPR 1 /* Structure will fit in 1 or 2 GPR */
#define STR_FPR 2 /* Structure will fit in a FPR */
#define STR_STACK 3 /* Structure needs to go on stack */
/*===================== End of Defines ===============================*/
/*====================================================================*/
/* Types */
/* ----- */
/*====================================================================*/
typedef struct stackLayout
{
int *backChain;
int *endOfStack;
int glue[2];
int scratch[2];
int gprArgs[MAX_GPRARGS];
int notUsed;
union
{
float f;
double d;
} fprArgs[MAX_FPRARGS];
int unUsed[8];
int outArgs[100];
} stackLayout;
/*======================== End of Types ==============================*/
/*====================================================================*/
/* Prototypes */
/* ---------- */
/*====================================================================*/
void ffi_prep_args(stackLayout *, extended_cif *);
static int ffi_check_struct(ffi_type *, unsigned int *);
static void ffi_insert_int(int, stackLayout *, int *, int *);
static void ffi_insert_int64(long long, stackLayout *, int *, int *);
static void ffi_insert_double(double, stackLayout *, int *, int *);
/*====================== End of Prototypes ===========================*/
/*====================================================================*/
/* Externals */
/* --------- */
/*====================================================================*/
extern void ffi_call_SYSV(void (*)(stackLayout *, extended_cif *),
extended_cif *,
unsigned, unsigned,
unsigned *,
void (*fn)());
/*====================== End of Externals ============================*/
/*====================================================================*/
/* */
/* Name - ffi_check_struct. */
/* */
/* Function - Determine if a structure can be passed within a */
/* general or floating point register. */
/* */
/*====================================================================*/
int
ffi_check_struct(ffi_type *arg, unsigned int *strFlags)
{
ffi_type *element;
int i_Element;
for (i_Element = 0; arg->elements[i_Element]; i_Element++) {
element = arg->elements[i_Element];
switch (element->type) {
case FFI_TYPE_DOUBLE :
*strFlags |= STR_FPR;
break;
case FFI_TYPE_STRUCT :
*strFlags |= ffi_check_struct(element, strFlags);
break;
default :
*strFlags |= STR_GPR;
}
}
return (*strFlags);
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_insert_int. */
/* */
/* Function - Insert an integer parameter in a register if there are */
/* spares else on the stack. */
/* */
/*====================================================================*/
void
ffi_insert_int(int gprValue, stackLayout *stack,
int *intArgC, int *outArgC)
{
if (*intArgC < MAX_GPRARGS) {
stack->gprArgs[*intArgC] = gprValue;
*intArgC += 1;
}
else {
stack->outArgs[*outArgC++] = gprValue;
*outArgC += 1;
}
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_insert_int64. */
/* */
/* Function - Insert a long long parameter in registers if there are */
/* spares else on the stack. */
/* */
/*====================================================================*/
void
ffi_insert_int64(long long llngValue, stackLayout *stack,
int *intArgC, int *outArgC)
{
if (*intArgC < (MAX_GPRARGS-1)) {
memcpy(&stack->gprArgs[*intArgC],
&llngValue, sizeof(long long));
*intArgC += 2;
}
else {
memcpy(&stack->outArgs[*outArgC],
&llngValue, sizeof(long long));
*outArgC += 2;
}
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_insert_double. */
/* */
/* Function - Insert a double parameter in a FP register if there is */
/* a spare else on the stack. */
/* */
/*====================================================================*/
void
ffi_insert_double(double dblValue, stackLayout *stack,
int *fprArgC, int *outArgC)
{
if (*fprArgC < MAX_FPRARGS) {
stack->fprArgs[*fprArgC].d = dblValue;
*fprArgC += 1;
}
else {
memcpy(&stack->outArgs[*outArgC],
&dblValue,sizeof(double));
*outArgC += 2;
}
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_prep_args. */
/* */
/* Function - Prepare parameters for call to function. */
/* */
/* ffi_prep_args is called by the assembly routine once stack space */
/* has been allocated for the function's arguments. */
/* */
/* The stack layout we want looks like this: */
/* *------------------------------------------------------------* */
/* | 0 | Back chain (a 0 here signifies end of back chain) | */
/* +--------+---------------------------------------------------+ */
/* | 4 | EOS (end of stack, not used on Linux for S390) | */
/* +--------+---------------------------------------------------+ */
/* | 8 | Glue used in other linkage formats | */
/* +--------+---------------------------------------------------+ */
/* | 12 | Glue used in other linkage formats | */
/* +--------+---------------------------------------------------+ */
/* | 16 | Scratch area | */
/* +--------+---------------------------------------------------+ */
/* | 20 | Scratch area | */
/* +--------+---------------------------------------------------+ */
/* | 24 | GPR parameter register 1 | */
/* +--------+---------------------------------------------------+ */
/* | 28 | GPR parameter register 2 | */
/* +--------+---------------------------------------------------+ */
/* | 32 | GPR parameter register 3 | */
/* +--------+---------------------------------------------------+ */
/* | 36 | GPR parameter register 4 | */
/* +--------+---------------------------------------------------+ */
/* | 40 | GPR parameter register 5 | */
/* +--------+---------------------------------------------------+ */
/* | 44 | Unused | */
/* +--------+---------------------------------------------------+ */
/* | 48 | FPR parameter register 1 | */
/* +--------+---------------------------------------------------+ */
/* | 56 | FPR parameter register 2 | */
/* +--------+---------------------------------------------------+ */
/* | 64 | Unused | */
/* +--------+---------------------------------------------------+ */
/* | 96 | Outgoing args (length x) | */
/* +--------+---------------------------------------------------+ */
/* | 96+x | Copy area for structures (length y) | */
/* +--------+---------------------------------------------------+ */
/* | 96+x+y | Possible stack alignment | */
/* *------------------------------------------------------------* */
/* */
/*====================================================================*/
void
ffi_prep_args(stackLayout *stack, extended_cif *ecif)
{
const unsigned bytes = ecif->cif->bytes;
const unsigned flags = ecif->cif->flags;
/*----------------------------------------------------------*/
/* Pointer to the copy area on stack for structures */
/*----------------------------------------------------------*/
char *copySpace = (char *) stack + bytes + sizeof(stackLayout);
/*----------------------------------------------------------*/
/* Count of general and floating point register usage */
/*----------------------------------------------------------*/
int intArgC = 0,
fprArgC = 0,
outArgC = 0;
int i;
ffi_type **ptr;
void **p_argv;
size_t structCopySize;
unsigned gprValue, strFlags = 0;
unsigned long long llngValue;
double dblValue;
/* Now for the arguments. */
p_argv = ecif->avalue;
/*----------------------------------------------------------------------*/
/* If we returning a structure then we set the first parameter register */
/* to the address of where we are returning this structure */
/*----------------------------------------------------------------------*/
if (flags == FFI_TYPE_STRUCT)
stack->gprArgs[intArgC++] = (int) ecif->rvalue;
for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
i > 0;
i--, ptr++, p_argv++)
{
switch ((*ptr)->type) {
case FFI_TYPE_FLOAT:
if (fprArgC < MAX_FPRARGS)
stack->fprArgs[fprArgC++].f = *(float *) *p_argv;
else
stack->outArgs[outArgC++] = *(int *) *p_argv;
break;
case FFI_TYPE_DOUBLE:
dblValue = *(double *) *p_argv;
ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
llngValue = *(unsigned long long *) *p_argv;
ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
break;
case FFI_TYPE_UINT8:
gprValue = *(unsigned char *)*p_argv;
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
case FFI_TYPE_SINT8:
gprValue = *(signed char *)*p_argv;
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
case FFI_TYPE_UINT16:
gprValue = *(unsigned short *)*p_argv;
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
case FFI_TYPE_SINT16:
gprValue = *(signed short *)*p_argv;
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
break;
case FFI_TYPE_STRUCT:
/*--------------------------------------------------*/
/* If structure > 8 bytes then it goes on the stack */
/*--------------------------------------------------*/
if (((*ptr)->size > 8) ||
((*ptr)->size > 4 &&
(*ptr)->size < 8))
strFlags = STR_STACK;
else
strFlags = ffi_check_struct((ffi_type *) *ptr, &strFlags);
switch (strFlags) {
/*-------------------------------------------*/
/* Structure that will fit in one or two GPR */
/*-------------------------------------------*/
case STR_GPR :
if ((*ptr)->size <= 4) {
gprValue = *(unsigned int *) *p_argv;
gprValue = gprValue >> ((4 - (*ptr)->size) * 8);
ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
}
else {
llngValue = *(unsigned long long *) *p_argv;
ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
}
break;
/*-------------------------------------------*/
/* Structure that will fit in one FPR */
/*-------------------------------------------*/
case STR_FPR :
dblValue = *(double *) *p_argv;
ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
break;
/*-------------------------------------------*/
/* Structure that must be copied to stack */
/*-------------------------------------------*/
default :
structCopySize = (((*ptr)->size + 15) & ~0xF);
copySpace -= structCopySize;
memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
gprValue = (unsigned) copySpace;
if (intArgC < MAX_GPRARGS)
stack->gprArgs[intArgC++] = gprValue;
else
stack->outArgs[outArgC++] = gprValue;
}
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
structCopySize = (((*ptr)->size + 15) & ~0xF);
copySpace -= structCopySize;
memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
gprValue = (unsigned) copySpace;
if (intArgC < MAX_GPRARGS)
stack->gprArgs[intArgC++] = gprValue;
else
stack->outArgs[outArgC++] = gprValue;
break;
#endif
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
gprValue = *(unsigned *)*p_argv;
if (intArgC < MAX_GPRARGS)
stack->gprArgs[intArgC++] = gprValue;
else
stack->outArgs[outArgC++] = gprValue;
break;
}
}
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_prep_cif_machdep. */
/* */
/* Function - Perform machine dependent CIF processing. */
/* */
/*====================================================================*/
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
int i;
ffi_type **ptr;
unsigned bytes;
int fpArgC = 0,
intArgC = 0;
unsigned flags = 0;
unsigned structCopySize = 0;
/*-----------------------------------------------------------------*/
/* Extra space required in stack for overflow parameters. */
/*-----------------------------------------------------------------*/
bytes = 0;
/*--------------------------------------------------------*/
/* Return value handling. The rules are as follows: */
/* - 32-bit (or less) integer values are returned in gpr2 */
/* - Structures are returned as pointers in gpr2 */
/* - 64-bit integer values are returned in gpr2 and 3 */
/* - Single/double FP values are returned in fpr0 */
/*--------------------------------------------------------*/
flags = cif->rtype->type;
/*------------------------------------------------------------------------*/
/* The first MAX_GPRARGS words of integer arguments, and the */
/* first MAX_FPRARGS floating point arguments, go in registers; the rest */
/* goes on the stack. Structures and long doubles (if not equivalent */
/* to double) are passed as a pointer to a copy of the structure. */
/* Stuff on the stack needs to keep proper alignment. */
/*------------------------------------------------------------------------*/
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
switch ((*ptr)->type)
{
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
fpArgC++;
if (fpArgC > MAX_FPRARGS && intArgC%2 != 0)
intArgC++;
break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
/*----------------------------------------------------*/
/* 'long long' arguments are passed as two words, but */
/* either both words must fit in registers or both go */
/* on the stack. If they go on the stack, they must */
/* be 8-byte-aligned. */
/*----------------------------------------------------*/
if ((intArgC == MAX_GPRARGS-1) ||
(intArgC >= MAX_GPRARGS) &&
(intArgC%2 != 0))
intArgC++;
intArgC += 2;
break;
case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
/*----------------------------------------------------*/
/* We must allocate space for a copy of these to */
/* enforce pass-by-value. Pad the space up to a */
/* multiple of 16 bytes (the maximum alignment */
/* required for anything under the SYSV ABI). */
/*----------------------------------------------------*/
structCopySize += ((*ptr)->size + 15) & ~0xF;
/*----------------------------------------------------*/
/* Fall through (allocate space for the pointer). */
/*----------------------------------------------------*/
default:
/*----------------------------------------------------*/
/* Everything else is passed as a 4-byte word in a */
/* GPR either the object itself or a pointer to it. */
/*----------------------------------------------------*/
intArgC++;
break;
}
}
/*-----------------------------------------------------------------*/
/* Stack space. */
/*-----------------------------------------------------------------*/
if (intArgC > MAX_GPRARGS)
bytes += (intArgC - MAX_GPRARGS) * sizeof(int);
if (fpArgC > MAX_FPRARGS)
bytes += (fpArgC - MAX_FPRARGS) * sizeof(double);
/*-----------------------------------------------------------------*/
/* The stack space allocated needs to be a multiple of 16 bytes. */
/*-----------------------------------------------------------------*/
bytes = (bytes + 15) & ~0xF;
/*-----------------------------------------------------------------*/
/* Add in the space for the copied structures. */
/*-----------------------------------------------------------------*/
bytes += structCopySize;
cif->flags = flags;
cif->bytes = bytes;
return FFI_OK;
}
/*======================== End of Routine ============================*/
/*====================================================================*/
/* */
/* Name - ffi_call. */
/* */
/* Function - Call the FFI routine. */
/* */
/*====================================================================*/
void
ffi_call(ffi_cif *cif,
void (*fn)(),
void *rvalue,
void **avalue)
{
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
/*-----------------------------------------------------------------*/
/* 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->rtype->type == FFI_TYPE_STRUCT))
ecif.rvalue = alloca(cif->rtype->size);
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
case FFI_SYSV:
ffi_call_SYSV(ffi_prep_args,
&ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
default:
FFI_ASSERT(0);
break;
}
}
/*======================== End of Routine ============================*/

161
libffi/src/s390/sysv.S Normal file
View File

@@ -0,0 +1,161 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 2000 Software AG
S390 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 CYGNUS SOLUTIONS 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 <ffi.h>
#ifdef HAVE_MACHINE_ASM_H
#include <machine/asm.h>
#endif
.text
# r2: ffi_prep_args
# r3: &ecif
# r4: cif->bytes
# r5: fig->flags
# r6: ecif.rvalue
# sp+0: fn
# This assumes we are using gas.
.globl ffi_call_SYSV
.type ffi_call_SYSV,%function
ffi_call_SYSV:
# Save registers
stm %r7,%r15,28(%r15)
l %r7,96(%r15) # Get A(fn)
lr %r0,%r15
ahi %r15,-128 # Make room for my args
st %r0,0(%r15) # Set backchain
lr %r11,%r15 # Establish my stack register
sr %r15,%r4 # Make room for fn args
ahi %r15,-96 # Make room for new frame
lr %r10,%r15 # Establish stack build area
ahi %r15,-96 # Stack for next call
lr %r1,%r7
stm %r2,%r7,96(%r11) # Save args on my stack
#------------------------------------------------------------------
# move first 3 parameters in registers
#------------------------------------------------------------------
lr %r9,%r2 # r9: &ffi_prep_args
lr %r2,%r10 # Parm 1: &stack Parm 2: &ecif
basr %r14,%r9 # call ffi_prep_args
#------------------------------------------------------------------
# load first 5 parameter registers
#------------------------------------------------------------------
lm %r2,%r6,24(%r10)
#------------------------------------------------------------------
# load fp parameter registers
#------------------------------------------------------------------
ld %f0,48(%r10)
ld %f2,56(%r10)
#------------------------------------------------------------------
# call function
#------------------------------------------------------------------
lr %r15,%r10 # Set new stack
l %r9,116(%r11) # Get &fn
basr %r14,%r9 # Call function
#------------------------------------------------------------------
# On return:
# r2: Return value (r3: Return value + 4 for long long)
#------------------------------------------------------------------
#------------------------------------------------------------------
# If the return value pointer is NULL, assume no return value.
#------------------------------------------------------------------
icm %r6,15,112(%r11)
jz .Lepilogue
l %r5,108(%r11) # Get return type
#------------------------------------------------------------------
# return INT
#------------------------------------------------------------------
chi %r5,FFI_TYPE_INT
jne .Lchk64
st %r2,0(%r6)
j .Lepilogue
.Lchk64:
#------------------------------------------------------------------
# return LONG LONG (signed/unsigned)
#------------------------------------------------------------------
chi %r5,FFI_TYPE_UINT64
je .LdoLongLong
chi %r5,FFI_TYPE_SINT64
jne .LchkFloat
.LdoLongLong:
stm %r2,%r3,0(%r6)
j .Lepilogue
.LchkFloat:
#------------------------------------------------------------------
# return FLOAT
#------------------------------------------------------------------
chi %r5,FFI_TYPE_FLOAT
jne .LchkDouble
std %f0,0(%r6)
j .Lepilogue
.LchkDouble:
#------------------------------------------------------------------
# return DOUBLE or LONGDOUBLE
#------------------------------------------------------------------
chi %r5,FFI_TYPE_DOUBLE
jne .LchkStruct
std %f0,0(%r6)
std %f2,8(%r6)
j .Lepilogue
.LchkStruct:
#------------------------------------------------------------------
# Structure - rvalue already set as sent as 1st parm to routine
#------------------------------------------------------------------
chi %r5,FFI_TYPE_STRUCT
je .Lepilogue
.Ldefault:
#------------------------------------------------------------------
# return a pointer
#------------------------------------------------------------------
st %r2,0(%r6)
j .Lepilogue
.Lepilogue:
l %r15,0(%r11)
l %r4,56(%r15)
lm %r7,%r15,28(%r15)
br %r4
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV

View File

@@ -3,8 +3,6 @@
Sparc Foreign Function Interface
$Id: ffi.c,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -33,7 +31,7 @@
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
void ffi_prep_args(char *stack, extended_cif *ecif)
void ffi_prep_args_v8(char *stack, extended_cif *ecif)
{
int i;
int tmp;
@@ -45,16 +43,16 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
tmp = 0;
/* Skip 16 words for the window save area */
argp = stack + 16*sizeof(void*);
argp = stack + 16*sizeof(int);
/* This should only really be done when we are returning a structure,
however, it's faster just to do it all the time...
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
*(void **) argp = ecif->rvalue;
*(int *) argp = (long)ecif->rvalue;
/* And 1 word for the structure return value. */
argp += sizeof(void*);
argp += sizeof(int);
#ifdef USING_PURIFY
/* Purify will probably complain in our assembly routine, unless we
@@ -81,10 +79,13 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
{
avn--;
if ((*p_arg)->type == FFI_TYPE_STRUCT
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE)
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE
#endif
)
{
*(unsigned int *) argp = (unsigned int)(* p_argv);
z = sizeof(void*);
*(unsigned int *) argp = (unsigned long)(* p_argv);
z = sizeof(int);
}
else
{
@@ -109,15 +110,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
case FFI_TYPE_UINT16:
*(unsigned int *) argp = *(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(signed int *) argp = *(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(unsigned int *) argp = *(UINT32 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
@@ -135,82 +128,295 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
return;
}
int ffi_prep_args_v9(char *stack, extended_cif *ecif)
{
int i, ret = 0;
int tmp;
void **p_argv;
char *argp;
ffi_type **p_arg;
tmp = 0;
/* Skip 16 words for the window save area */
argp = stack + 16*sizeof(long long);
#ifdef USING_PURIFY
/* Purify will probably complain in our assembly routine, unless we
zero out this memory. */
((long long*)argp)[0] = 0;
((long long*)argp)[1] = 0;
((long long*)argp)[2] = 0;
((long long*)argp)[3] = 0;
((long long*)argp)[4] = 0;
((long long*)argp)[5] = 0;
#endif
p_argv = ecif->avalue;
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
ecif->cif->rtype->size > 32)
{
*(unsigned long long *) argp = (unsigned long)ecif->rvalue;
tmp = 1;
}
for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
i++, p_arg++)
{
size_t z;
z = (*p_arg)->size;
switch ((*p_arg)->type)
{
case FFI_TYPE_STRUCT:
if (z > 16)
{
/* For structures larger than 16 bytes we pass reference. */
*(unsigned long long *) argp = (unsigned long)* p_argv;
argp += sizeof(long long);
tmp++;
p_argv++;
continue;
}
/* FALLTHROUGH */
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
ret = 1; /* We should promote into FP regs as well as integer. */
break;
}
if (z < sizeof(long long))
{
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(signed long long *) argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(unsigned long long *) argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(signed long long *) argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(unsigned long long *) argp = *(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(signed long long *) argp = *(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(unsigned long long *) argp = *(UINT32 *)(* p_argv);
break;
case FFI_TYPE_FLOAT:
*(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
break;
case FFI_TYPE_STRUCT:
memcpy(argp, *p_argv, z);
break;
default:
FFI_ASSERT(0);
}
z = sizeof(long long);
tmp++;
}
else if (z == sizeof(long long))
{
memcpy(argp, *p_argv, z);
z = sizeof(long long);
tmp++;
}
else
{
if ((tmp & 1) && (*p_arg)->alignment > 8)
{
tmp++;
argp += sizeof(long long);
}
memcpy(argp, *p_argv, z);
z = 2 * sizeof(long long);
tmp += 2;
}
p_argv++;
argp += z;
}
return ret;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* If we are returning a struct, this will already have been added.
Otherwise we need to add it because it's always got to be there! */
int wordsize;
if (cif->rtype->type != FFI_TYPE_STRUCT)
cif->bytes += sizeof(void*);
if (cif->abi != FFI_V9)
{
wordsize = 4;
/* sparc call frames require that space is allocated for 6 args,
even if they aren't used. Make that space if necessary. */
/* If we are returning a struct, this will already have been added.
Otherwise we need to add it because it's always got to be there! */
if (cif->rtype->type != FFI_TYPE_STRUCT)
cif->bytes += wordsize;
/* sparc call frames require that space is allocated for 6 args,
even if they aren't used. Make that space if necessary. */
if (cif->bytes < 4*6+4)
cif->bytes = 4*6+4;
if (cif->bytes < 4*6+4)
cif->bytes = 4*6+4;
}
else
{
wordsize = 8;
/* sparc call frames require that space is allocated for 6 args,
even if they aren't used. Make that space if necessary. */
if (cif->bytes < 8*6)
cif->bytes = 8*6;
}
/* Adjust cif->bytes. to include 16 words for the window save area,
and maybe the struct/union return pointer area, */
cif->bytes += 64;
cif->bytes += 16 * wordsize;
/* The stack must be double word aligned, so round bytes up
/* The stack must be 2 word aligned, so round bytes up
appropriately. */
cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
cif->flags = cif->rtype->type;
break;
case FFI_TYPE_FLOAT:
cif->flags = FFI_TYPE_FLOAT;
break;
case FFI_TYPE_DOUBLE:
cif->flags = FFI_TYPE_DOUBLE;
case FFI_TYPE_STRUCT:
if (cif->abi == FFI_V9 && cif->rtype->size > 32)
cif->flags = FFI_TYPE_VOID;
else
cif->flags = FFI_TYPE_STRUCT;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
if (cif->abi != FFI_V9)
{
cif->flags = FFI_TYPE_SINT64;
break;
}
/* FALLTHROUGH */
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
int ffi_V9_return_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
{
ffi_type **ptr = &arg->elements[0];
while (*ptr != NULL)
{
if (off & ((*ptr)->alignment - 1))
off = ALIGN(off, (*ptr)->alignment);
switch ((*ptr)->type)
{
case FFI_TYPE_STRUCT:
off = ffi_V9_return_struct(*ptr, off, ret, intg, flt);
break;
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
memcpy(ret + off, flt + off, (*ptr)->size);
off += (*ptr)->size;
break;
default:
memcpy(ret + off, intg + off, (*ptr)->size);
off += (*ptr)->size;
break;
}
ptr++;
}
return off;
}
extern int ffi_call_V8(void *, extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)());
extern int ffi_call_V9(void *, extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)());
void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{
extended_cif ecif;
void *rval = rvalue;
ecif.cif = cif;
ecif.avalue = avalue;
/* 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->rtype->type == FFI_TYPE_STRUCT))
ecif.rvalue = alloca(cif->rtype->size);
else
ecif.rvalue = rvalue;
ecif.rvalue = rvalue;
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
if (cif->rtype->size <= 32)
rval = alloca(64);
else
{
rval = NULL;
if (rvalue == NULL)
ecif.rvalue = alloca(cif->rtype->size);
}
}
switch (cif->abi)
{
case FFI_V8:
ffi_call_V8(ffi_prep_args, &ecif, cif->bytes,
#ifdef SPARC64
/* We don't yet support calling 32bit code from 64bit */
FFI_ASSERT(0);
#else
ffi_call_V8(ffi_prep_args_v8, &ecif, cif->bytes,
cif->flags, rvalue, fn);
#endif
break;
case FFI_V9:
#ifdef SPARC64
ffi_call_V9(ffi_prep_args_v9, &ecif, cif->bytes,
cif->flags, rval, fn);
if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
ffi_V9_return_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
#else
/* And vice versa */
FFI_ASSERT(0);
#endif
break;
default:
FFI_ASSERT(0);
break;
}
}

View File

@@ -3,8 +3,6 @@
Sparc Foreign Function Interface
$Id: v8.S,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -56,6 +54,7 @@ _ffi_call_V8:
ld [%l0+ARGS+20], %o5
call %i5
mov %l0, %sp ! (delay) switch to frame
nop ! STRUCT returning functions skip 12 instead of 8 bytes
! If the return value pointer is NULL, assume no return value.
tst %i4
@@ -70,6 +69,9 @@ _ffi_call_V8:
be,a done
st %f0, [%i4+0] ! (delay)
cmp %i3, FFI_TYPE_SINT64
be longlong
cmp %i3, FFI_TYPE_DOUBLE
bne done
nop
@@ -80,6 +82,12 @@ done:
ret
restore
longlong:
st %o0, [%i4+0]
st %o1, [%i4+4]
ret
restore
.ffi_call_V8_end:
.size ffi_call_V8,.ffi_call_V8_end-ffi_call_V8

View File

@@ -3,8 +3,6 @@
Sparc 64bit Foreign Function Interface
$Id: v9.S,v 1.1 2000/04/17 03:18:46 green Exp $
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

View File

@@ -3,8 +3,6 @@
Predefined ffi_types needed by libffi.
$Id: types.c,v 1.1 1998/11/29 16:48:16 green Exp $
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
@@ -19,7 +17,7 @@
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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
IN NO EVENT SHALL RED HAT 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.
@@ -42,15 +40,28 @@ FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16);
FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16);
FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32);
FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
#if defined ALPHA || defined SPARC64
FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
#else
FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
#endif
#ifdef X86
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
#elif defined X86_WIN32
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
#elif defined ARM
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
@@ -74,6 +85,11 @@ FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64);
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
#elif defined X86_WIN32
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
#elif defined ARM
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
@@ -87,8 +103,17 @@ FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
#elif defined SPARC
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
#ifdef SPARC64
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
#else
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
#endif
#else
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);

View File

@@ -3,8 +3,6 @@
x86 Foreign Function Interface
$Id: ffi.c,v 1.3 1999/08/08 13:05:12 green Exp $
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

View File

@@ -3,8 +3,6 @@
X86 Foreign Function Interface
$Id: sysv.S,v 1.2 1999/08/04 18:00:05 green Exp $
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
@@ -38,9 +36,11 @@
.type ffi_call_SYSV,@function
ffi_call_SYSV:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp,%ebp
.LCFI1:
# Make room for all of the new args.
movl 16(%ebp),%ecx
subl %ecx,%esp
@@ -124,6 +124,43 @@ epilogue:
movl %ebp,%esp
popl %ebp
ret
.LFE1:
.ffi_call_SYSV_end:
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
.section .eh_frame,"aw",@progbits
__FRAME_BEGIN__:
.4byte .LLCIE1
.LSCIE1:
.4byte 0x0
.byte 0x1
.byte 0x0
.byte 0x1
.byte 0x7c
.byte 0x8
.byte 0xc
.byte 0x4
.byte 0x4
.byte 0x88
.byte 0x1
.align 4
.LECIE1:
.set .LLCIE1,.LECIE1-.LSCIE1
.4byte .LLFDE1
.LSFDE1:
.4byte .LSFDE1-__FRAME_BEGIN__
.4byte .LFB1
.4byte .LFE1-.LFB1
.byte 0x4
.4byte .LCFI0-.LFB1
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.4byte .LCFI1-.LCFI0
.byte 0xd
.byte 0x5
.align 4
.LEFDE1:
.set .LLFDE1,.LEFDE1-.LSFDE1

125
libffi/src/x86/win32.S Normal file
View File

@@ -0,0 +1,125 @@
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001 Cygnus Solutions
X86 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 CYGNUS SOLUTIONS 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 <ffi.h>
.text
.globl ffi_prep_args
# This assumes we are using gas.
.balign 16
.globl _ffi_call_SYSV
_ffi_call_SYSV:
pushl %ebp
movl %esp,%ebp
# Make room for all of the new args.
movl 16(%ebp),%ecx
subl %ecx,%esp
movl %esp,%eax
# Place all of the ffi_prep_args in position
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
# Return stack to previous state and call the function
addl $8,%esp
call *28(%ebp)
# Remove the space we pushed for the args
movl 16(%ebp),%ecx
addl %ecx,%esp
# Load %ecx with the return type code
movl 20(%ebp),%ecx
# If the return value pointer is NULL, assume no return value.
cmpl $0,24(%ebp)
jne retint
# Even if there is no space for the return value, we are
# obliged to handle floating-point values.
cmpl $FFI_TYPE_FLOAT,%ecx
jne noretval
fstp %st(0)
jmp epilogue
retint:
cmpl $FFI_TYPE_INT,%ecx
jne retfloat
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
jmp epilogue
retfloat:
cmpl $FFI_TYPE_FLOAT,%ecx
jne retdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstps (%ecx)
jmp epilogue
retdouble:
cmpl $FFI_TYPE_DOUBLE,%ecx
jne retlongdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpl (%ecx)
jmp epilogue
retlongdouble:
cmpl $FFI_TYPE_LONGDOUBLE,%ecx
jne retint64
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpt (%ecx)
jmp epilogue
retint64:
cmpl $FFI_TYPE_SINT64,%ecx
jne retstruct
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
retstruct:
# Nothing to do!
noretval:
epilogue:
movl %ebp,%esp
popl %ebp
ret
.ffi_call_SYSV_end: